ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.assClozeTestGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestionGUI.php';
5 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiQuestionScoringAdjustable.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiAnswerScoringAdjustable.php';
7 
24 {
25  const OLD_CLOZE_TEST_UI = false;
26 
30  private $gapIndex;
31 
37  public function __construct($id = -1)
38  {
39  parent::__construct();
40  include_once "./Modules/TestQuestionPool/classes/class.assClozeTest.php";
41  $this->object = new assClozeTest();
42  if ($id >= 0) {
43  $this->object->loadFromDb($id);
44  }
45  }
46 
47  public function getCommand($cmd)
48  {
49  if (preg_match("/^(removegap|addgap)_(\d+)$/", $cmd, $matches)) {
50  $cmd = $matches[1];
51  $this->gapIndex = $matches[2];
52  }
53  return $cmd;
54  }
55 
59  protected function writePostData($always = false)
60  {
61  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
62  if (!$hasErrors) {
63  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
64 
65  $cloze_text = $this->object->getHtmlQuestionContentPurifier()->purify($_POST['cloze_text']);
66 
67  $cloze_text = $this->removeIndizesFromGapText($cloze_text);
68  $_POST['cloze_text'] = $cloze_text;
69  $this->object->setQuestion($_POST['question']);
70 
72  $this->object->setClozeText($_POST["cloze_text"]);
74  //$this->object->flushGaps();
76  $this->saveTaxonomyAssignments();
77  return 0;
78  }
79 
80  $cloze_text = $_POST['cloze_text'];
81  $cloze_text = $this->applyIndizesToGapText($cloze_text);
82  $_POST['cloze_text'] = $cloze_text;
83  return 1;
84  }
85 
87  {
88  if (is_array($_POST['gap'])) {
89  if ($this->ctrl->getCmd() != 'createGaps') {
90  $this->object->clearGapAnswers();
91  }
92 
93  foreach ($_POST['gap'] as $idx => $hidden) {
94  $clozetype = $_POST['clozetype_' . $idx];
95 
96  $this->object->setGapType($idx, $clozetype);
97 
98  switch ($clozetype) {
99  case CLOZE_TEXT:
100 
101  $this->object->setGapShuffle($idx, 0);
102 
103  if ($this->ctrl->getCmd() != 'createGaps') {
104  if (is_array($_POST['gap_' . $idx]['answer'])) {
105  foreach ($_POST['gap_' . $idx]['answer'] as $order => $value) {
106  $this->object->addGapAnswer($idx, $order, $value);
107  }
108  } else {
109  $this->object->addGapAnswer($idx, 0, '');
110  }
111  }
112 
113  if (is_array($_POST['gap_' . $idx]['points'])) {
114  foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
115  $this->object->setGapAnswerPoints($idx, $order, $value);
116  }
117  }
118 
119  if (array_key_exists('gap_' . $idx . '_gapsize', $_POST)) {
120  $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize']);
121  }
122 
123  break;
124 
125  case CLOZE_SELECT:
126 
127  $this->object->setGapShuffle($idx, (int) (isset($_POST["shuffle_$idx"]) && $_POST["shuffle_$idx"]));
128 
129  if ($this->ctrl->getCmd() != 'createGaps') {
130  if (is_array($_POST['gap_' . $idx]['answer'])) {
131  foreach ($_POST['gap_' . $idx]['answer'] as $order => $value) {
132  $this->object->addGapAnswer($idx, $order, $value);
133  }
134  } else {
135  $this->object->addGapAnswer($idx, 0, '');
136  }
137  }
138 
139  if (is_array($_POST['gap_' . $idx]['points'])) {
140  foreach ($_POST['gap_' . $idx]['points'] as $order => $value) {
141  $this->object->setGapAnswerPoints($idx, $order, $value);
142  }
143  }
144  break;
145 
146  case CLOZE_NUMERIC:
147 
148  $this->object->setGapShuffle($idx, 0);
149 
150  $gap = $this->object->getGap($idx);
151  if (!$gap) {
152  break;
153  }
154 
155  $this->object->getGap($idx)->clearItems();
156 
157  if (array_key_exists('gap_' . $idx . '_numeric', $_POST)) {
158  if ($this->ctrl->getCmd() != 'createGaps') {
159  $this->object->addGapAnswer(
160  $idx,
161  0,
162  str_replace(",", ".", $_POST['gap_' . $idx . '_numeric'])
163  );
164  }
165 
166  $this->object->setGapAnswerLowerBound(
167  $idx,
168  0,
169  str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_lower'])
170  );
171 
172  $this->object->setGapAnswerUpperBound(
173  $idx,
174  0,
175  str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_upper'])
176  );
177 
178  $this->object->setGapAnswerPoints($idx, 0, $_POST['gap_' . $idx . '_numeric_points']);
179  } else {
180  if ($this->ctrl->getCmd() != 'createGaps') {
181  $this->object->addGapAnswer($idx, 0, '');
182  }
183 
184  $this->object->setGapAnswerLowerBound($idx, 0, '');
185 
186  $this->object->setGapAnswerUpperBound($idx, 0, '');
187  }
188 
189  if (array_key_exists('gap_' . $idx . '_gapsize', $_POST)) {
190  $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize']);
191  }
192  break;
193  }
194  $assClozeGapCombinationObject = new assClozeGapCombination();
195  $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->object->getId());
196  if (is_array($_POST['gap_combination']) && count($_POST['gap_combination']) > 0) {
197  $assClozeGapCombinationObject->saveGapCombinationToDb($this->object->getId(), ilUtil::stripSlashesRecursive($_POST['gap_combination']), ilUtil::stripSlashesRecursive($_POST['gap_combination_values']));
198  }
199  }
200  if ($this->ctrl->getCmd() != 'createGaps') {
201  $this->object->updateClozeTextFromGaps();
202  }
203  }
204  }
205 
207  {
208  $this->object->setClozeText($_POST['cloze_text']);
209  $this->object->setTextgapRating($_POST["textgap_rating"]);
210  $this->object->setIdenticalScoring($_POST["identical_scoring"]);
211  $this->object->setFixedTextLength($_POST["fixedTextLength"]);
212  }
213 
219  public function editQuestion($checkonly = false)
220  {
221  $save = $this->isSaveCommand();
222  $this->getQuestionTemplate();
223 
224  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
225  $form = new ilPropertyFormGUI();
226  $this->editForm = $form;
227 
228  $form->setFormAction($this->ctrl->getFormAction($this));
229  $form->setTitle($this->outQuestionType());
230  $form->setMultipart(false);
231  $form->setTableWidth("100%");
232  $form->setId("assclozetest");
233 
234  // title, author, description, question, working time (assessment mode)
239 
241 
242  $errors = false;
243 
244  if ($save) {
245  $form->setValuesByPost();
246  $errors = !$form->checkInput();
247  $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we
248  // need this if we don't want to have duplication of backslashes
249  if ($errors) {
250  $checkonly = false;
251  }
252  }
253 
254  if (!$checkonly) {
255  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
256  }
257  return $errors;
258  }
259 
261  {
262  // title
263  $title = new ilTextInputGUI($this->lng->txt("title"), "title");
264  $title->setMaxLength(100);
265  $title->setValue($this->object->getTitle());
266  $title->setRequired(true);
267  $form->addItem($title);
268 
269  if (!$this->object->getSelfAssessmentEditingMode()) {
270  // author
271  $author = new ilTextInputGUI($this->lng->txt("author"), "author");
272  $author->setValue($this->object->getAuthor());
273  $author->setRequired(true);
274  $form->addItem($author);
275 
276  // description
277  $description = new ilTextInputGUI($this->lng->txt("description"), "comment");
278  $description->setValue($this->object->getComment());
279  $description->setRequired(false);
280  $form->addItem($description);
281  } else {
282  // author as hidden field
283  $hi = new ilHiddenInputGUI("author");
284  $author = ilUtil::prepareFormOutput($this->object->getAuthor());
285  if (trim($author) == "") {
286  $author = "-";
287  }
288  $hi->setValue($author);
289  $form->addItem($hi);
290  }
291 
292  // questiontext
293  $question = new ilTextAreaInputGUI($this->lng->txt("question"), "question");
294  $question->setValue($this->object->prepareTextareaOutput($this->object->getQuestion()));
295  $question->setRequired(true);
296  $question->setRows(10);
297  $question->setCols(80);
298  if (!$this->object->getSelfAssessmentEditingMode()) {
299  if ($this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT) {
300  $question->setUseRte(true);
301  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
302  $question->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
303  $question->addPlugin("latex");
304  $question->addButton("latex");
305  $question->addButton("pastelatex");
306  $question->setRTESupport($this->object->getId(), "qpl", "assessment");
307  }
308  } else {
309  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
311  $question->setUseTagsForRteOnly(false);
312  }
313  $form->addItem($question);
314 
315  // $tpl = new ilTemplate("tpl.il_as_qpl_cloze_gap_button_code.html", TRUE, TRUE, "Modules/TestQuestionPool");
316  // $tpl->setVariable('INSERT_GAP', $this->lng->txt('insert_gap'));
317  // $tpl->setVariable('CREATE_GAPS', $this->lng->txt('create_gaps'));
318  // $tpl->parseCurrentBlock();
319  // $button = new ilCustomInputGUI('&nbsp;','');
320  // $button->setHtml($tpl->get());
321  // $form->addItem($button);
322 
323  if (!$this->object->getSelfAssessmentEditingMode()) {
324  // duration
325  $duration = new ilDurationInputGUI($this->lng->txt("working_time"), "Estimated");
326  $duration->setShowHours(true);
327  $duration->setShowMinutes(true);
328  $duration->setShowSeconds(true);
329  $ewt = $this->object->getEstimatedWorkingTime();
330  $duration->setHours($ewt["h"]);
331  $duration->setMinutes($ewt["m"]);
332  $duration->setSeconds($ewt["s"]);
333  $duration->setRequired(false);
334  $form->addItem($duration);
335  } else {
336  // number of tries
337  if (strlen($this->object->getNrOfTries())) {
338  $nr_tries = $this->object->getNrOfTries();
339  } else {
340  $nr_tries = $this->object->getDefaultNrOfTries();
341  }
342  /*if ($nr_tries <= 0)
343  {
344  $nr_tries = 1;
345  }*/
346 
347  if ($nr_tries < 0) {
348  $nr_tries = 0;
349  }
350 
351  $ni = new ilNumberInputGUI($this->lng->txt("qst_nr_of_tries"), "nr_of_tries");
352  $ni->setValue($nr_tries);
353  //$ni->setMinValue(1);
354  $ni->setMinValue(0);
355  $ni->setSize(5);
356  $ni->setMaxLength(5);
357  $ni->setRequired(true);
358  $form->addItem($ni);
359  }
360  }
361 
363  {
364  // cloze text
365  $cloze_text = new ilTextAreaInputGUI($this->lng->txt("cloze_text"), 'cloze_text');
366  $cloze_text->setRequired(true);
367  $cloze_text->setValue($this->applyIndizesToGapText($this->object->getClozeText()));
368  $cloze_text->setInfo($this->lng->txt("close_text_hint"));
369  $cloze_text->setRows(10);
370  $cloze_text->setCols(80);
371  if (!$this->object->getSelfAssessmentEditingMode()) {
372  if ($this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT) {
373  $cloze_text->setUseRte(true);
374  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
375  $cloze_text->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
376  $cloze_text->addPlugin("latex");
377  $cloze_text->addButton("latex");
378  $cloze_text->addButton("pastelatex");
379  }
380  } else {
381  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
383  $cloze_text->setUseTagsForRteOnly(false);
384  }
385  $cloze_text->setRTESupport($this->object->getId(), "qpl", "assessment");
386  $form->addItem($cloze_text);
387 
388  $tpl = new ilTemplate("tpl.il_as_qpl_cloze_gap_button_code.html", true, true, "Modules/TestQuestionPool");
389 
390  $button = new ilCustomInputGUI('&nbsp;', '');
391  require_once 'Services/UIComponent/SplitButton/classes/class.ilSplitButtonGUI.php';
392  require_once 'Services/UIComponent/Button/classes/class.ilJsLinkButton.php';
393  $action_button = ilSplitButtonGUI::getInstance();
394 
395  $sb_text_gap = ilJsLinkButton::getInstance();
396  $sb_text_gap->setCaption('text_gap');
397  $sb_text_gap->setName('gapbutton');
398  $sb_text_gap->setId('gaptrigger_text');
399  $action_button->setDefaultButton($sb_text_gap);
400 
401  $sb_sel_gap = ilJsLinkButton::getInstance();
402  $sb_sel_gap->setCaption('select_gap');
403  $sb_sel_gap->setName('gapbutton_select');
404  $sb_sel_gap->setId('gaptrigger_select');
405  $action_button->addMenuItem(new ilButtonToSplitButtonMenuItemAdapter($sb_sel_gap));
406 
407  $sb_num_gap = ilJsLinkButton::getInstance();
408  $sb_num_gap->setCaption('numeric_gap');
409  $sb_num_gap->setName('gapbutton_numeric');
410  $sb_num_gap->setId('gaptrigger_numeric');
411  $action_button->addMenuItem(new ilButtonToSplitButtonMenuItemAdapter($sb_num_gap));
412 
413  $tpl->setVariable('BUTTON', $action_button->render());
414  $tpl->parseCurrentBlock();
415 
416  $button->setHtml($tpl->get());
417  $form->addItem($button);
418 
419  // text rating
420  if (!$this->object->getSelfAssessmentEditingMode()) {
421  $textrating = new ilSelectInputGUI($this->lng->txt("text_rating"), "textgap_rating");
422  $text_options = array(
423  "ci" => $this->lng->txt("cloze_textgap_case_insensitive"),
424  "cs" => $this->lng->txt("cloze_textgap_case_sensitive"),
425  "l1" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "1"),
426  "l2" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "2"),
427  "l3" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "3"),
428  "l4" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "4"),
429  "l5" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "5")
430  );
431  $textrating->setOptions($text_options);
432  $textrating->setValue($this->object->getTextgapRating());
433  $form->addItem($textrating);
434 
435  // text field length
436  $fixedTextLength = new ilNumberInputGUI($this->lng->txt("cloze_fixed_textlength"), "fixedTextLength");
437  $ftl = $this->object->getFixedTextLength();
438 
439  $fixedTextLength->setValue($ftl > 0 ? $ftl : '');
440  $fixedTextLength->setMinValue(0);
441  $fixedTextLength->setSize(3);
442  $fixedTextLength->setMaxLength(6);
443  $fixedTextLength->setInfo($this->lng->txt('cloze_fixed_textlength_description'));
444  $fixedTextLength->setRequired(false);
445  $form->addItem($fixedTextLength);
446 
447  // identical scoring
448  $identical_scoring = new ilCheckboxInputGUI($this->lng->txt("identical_scoring"), "identical_scoring");
449  $identical_scoring->setValue(1);
450  $identical_scoring->setChecked($this->object->getIdenticalScoring());
451  $identical_scoring->setInfo($this->lng->txt('identical_scoring_desc'));
452  $identical_scoring->setRequired(false);
453  $form->addItem($identical_scoring);
454  }
455  return $form;
456  }
457 
459  {
460  if (self::OLD_CLOZE_TEST_UI) {
461  for ($gapCounter = 0; $gapCounter < $this->object->getGapCount(); $gapCounter++) {
462  $this->populateGapFormPart($form, $gapCounter);
463  }
464  return $form;
465  } else {
466  require_once 'Modules/TestQuestionPool/classes/Form/class.ilClozeGapInputBuilderGUI.php';
467  $json=$this->populateJSON();
468  $assClozeGapCombinationObject = new assClozeGapCombination();
469  $combination_exists = $assClozeGapCombinationObject->combinationExistsForQid($this->object->id);
470  if ($combination_exists) {
471  $combinations = $assClozeGapCombinationObject->loadFromDb($this->object->id);
472  }
473  $new_builder = new ilClozeGapInputBuilderGUI();
475  $form->addItem($header);
476  $new_builder->setValueByArray($json);
477  $new_builder->setValueCombinationFromDb($combinations);
478  $form->addItem($new_builder);
479  return $form;
480  }
481  }
482 
483  protected function populateJSON()
484  {
485  $gap = $this->object->getGaps();
486  $array = array();
487  if ($gap == null) {
488  return $array;
489  }
490  $translate_type=array('text','select','numeric');
491  $i = 0;
492  foreach ($gap as $content) {
493  $shuffle=false;
494  $value=$content->getItemsRaw();
495  $items=array();
496  for ($j=0;$j<count($value);$j++) {
497  if ($content->getType()==2) {
498  $items[$j] = array(
499  'answer' => $value[$j]->getAnswerText(),
500  'lower' => $value[$j]->getLowerBound(),
501  'upper' => $value[$j]->getUpperBound(),
502  'points' => $value[$j]->getPoints(),
503  'error' => false
504  );
505  } else {
506  $items[$j] = array(
507  'answer' => $value[$j]->getAnswerText(),
508  'points' => $value[$j]->getPoints(),
509  'error' => false
510  );
511 
512  if ($content->getType()==1) {
513  $shuffle=$content->getShuffle();
514  }
515  }
516  }
517  $answers[$i]=array(
518  'type' => $translate_type[$content->getType()] ,
519  'values' => $items ,
520  'shuffle' => $shuffle,
521  'text_field_length' => $content->getGapSize() > 0 ? $content->getGapSize() : '',
522  'used_in_gap_combination' => true);
523  $i++;
524  }
525  return $answers;
526  }
538  protected function populateGapFormPart($form, $gapCounter)
539  {
540  $gap = $this->object->getGap($gapCounter);
541 
542  if ($gap == null) {
543  return $form;
544  }
545 
547  $header->setTitle($this->lng->txt("gap") . " " . ($gapCounter + 1));
548  $form->addItem($header);
549 
550  $gapcounter = new ilHiddenInputGUI("gap[$gapCounter]");
551  $gapcounter->setValue($gapCounter);
552  $form->addItem($gapcounter);
553 
554  $gaptype = new ilSelectInputGUI($this->lng->txt('type'), "clozetype_$gapCounter");
555  $options = array(
556  0 => $this->lng->txt("text_gap"),
557  1 => $this->lng->txt("select_gap"),
558  2 => $this->lng->txt("numeric_gap")
559  );
560  $gaptype->setOptions($options);
561  $gaptype->setValue($gap->getType());
562  $form->addItem($gaptype);
563 
564  if ($gap->getType() == CLOZE_TEXT) {
565  $this->populateGapSizeFormPart($form, $gap, $gapCounter);
566 
567  if (count($gap->getItemsRaw()) == 0) {
568  $gap->addItem(new assAnswerCloze("", 0, 0));
569  }
570  $this->populateTextGapFormPart($form, $gap, $gapCounter);
571  } elseif ($gap->getType() == CLOZE_SELECT) {
572  if (count($gap->getItemsRaw()) == 0) {
573  $gap->addItem(new assAnswerCloze("", 0, 0));
574  }
575  $this->populateSelectGapFormPart($form, $gap, $gapCounter);
576  } elseif ($gap->getType() == CLOZE_NUMERIC) {
577  $this->populateGapSizeFormPart($form, $gap, $gapCounter);
578 
579  if (count($gap->getItemsRaw()) == 0) {
580  $gap->addItem(new assAnswerCloze("", 0, 0));
581  }
582  foreach ($gap->getItemsRaw() as $item) {
583  $this->populateNumericGapFormPart($form, $item, $gapCounter);
584  }
585  }
586  return $form;
587  }
588 
594  protected function populateGapSizeFormPart($form, $gap, $gapCounter)
595  {
596  $gapSizeFormItem = new ilNumberInputGUI($this->lng->txt('cloze_fixed_textlength'), "gap_" . $gapCounter . '_gapsize');
597 
598  $gapSizeFormItem->allowDecimals(false);
599  $gapSizeFormItem->setMinValue(0);
600  $gapSizeFormItem->setSize(3);
601  $gapSizeFormItem->setMaxLength(6);
602  $gapSizeFormItem->setInfo($this->lng->txt('cloze_gap_size_info'));
603  $gapSizeFormItem->setValue($gap->getGapSize());
604  $form->addItem($gapSizeFormItem);
605 
606  return $form;
607  }
608 
621  protected function populateSelectGapFormPart($form, $gap, $gapCounter)
622  {
623  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
624  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
625  $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $gapCounter . "");
626  $values->setRequired(true);
627  $values->setQuestionObject($this->object);
628  $values->setSingleline(true);
629  $values->setAllowMove(false);
630 
631  $values->setValues($gap->getItemsRaw());
632  $form->addItem($values);
633 
634  // shuffle
635  $shuffle = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_" . $gapCounter . "");
636  $shuffle->setValue(1);
637  $shuffle->setChecked($gap->getShuffle());
638  $shuffle->setRequired(false);
639  $form->addItem($shuffle);
640  return $form;
641  }
642 
654  protected function populateTextGapFormPart($form, $gap, $gapCounter)
655  {
656  // Choices
657  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
658  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
659  $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $gapCounter . "");
660  $values->setRequired(true);
661  $values->setQuestionObject($this->object);
662  $values->setSingleline(true);
663  $values->setAllowMove(false);
664  $values->setValues($gap->getItemsRaw());
665  $form->addItem($values);
666 
667  if ($this->object->getFixedTextLength() > 0) {
668  $values->setSize($this->object->getFixedTextLength());
669  $values->setMaxLength($this->object->getFixedTextLength());
670  }
671 
672  return $form;
673  }
674 
686  protected function populateNumericGapFormPart($form, $gap, $gapCounter)
687  {
688  // #8944: the js-based ouput in self-assessment cannot support formulas
689  if (!$this->object->getSelfAssessmentEditingMode()) {
690  $value = new ilFormulaInputGUI($this->lng->txt('value'), "gap_" . $gapCounter . "_numeric");
691  $value->setInlineStyle('text-align: right;');
692 
693  $lowerbound = new ilFormulaInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
694  $lowerbound->setInlineStyle('text-align: right;');
695 
696  $upperbound = new ilFormulaInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
697  $upperbound->setInlineStyle('text-align: right;');
698  } else {
699  $value = new ilNumberInputGUI($this->lng->txt('value'), "gap_" . $gapCounter . "_numeric");
700  $value->allowDecimals(true);
701 
702  $lowerbound = new ilNumberInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
703  $lowerbound->allowDecimals(true);
704 
705  $upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
706  $upperbound->allowDecimals(true);
707  }
708 
709  $value->setSize(10);
710  $value->setValue(ilUtil::prepareFormOutput($gap->getAnswertext()));
711  $value->setRequired(true);
712  $form->addItem($value);
713 
714  $lowerbound->setSize(10);
715  $lowerbound->setRequired(true);
716  $lowerbound->setValue(ilUtil::prepareFormOutput($gap->getLowerBound()));
717  $form->addItem($lowerbound);
718 
719  $upperbound->setSize(10);
720  $upperbound->setRequired(true);
721  $upperbound->setValue(ilUtil::prepareFormOutput($gap->getUpperBound()));
722  $form->addItem($upperbound);
723 
724  if ($this->object->getFixedTextLength() > 0) {
725  $value->setSize($this->object->getFixedTextLength());
726  $value->setMaxLength($this->object->getFixedTextLength());
727  $lowerbound->setSize($this->object->getFixedTextLength());
728  $lowerbound->setMaxLength($this->object->getFixedTextLength());
729  $upperbound->setSize($this->object->getFixedTextLength());
730  $upperbound->setMaxLength($this->object->getFixedTextLength());
731  }
732 
733  $points = new ilNumberInputGUI($this->lng->txt('points'), "gap_" . $gapCounter . "_numeric_points");
734  $points->allowDecimals(true);
735  $points->setSize(3);
736  $points->setRequired(true);
737  $points->setValue(ilUtil::prepareFormOutput($gap->getPoints()));
738  $form->addItem($points);
739  return $form;
740  }
741 
745  public function createGaps()
746  {
747  $this->writePostData(true);
748  $this->object->saveToDb();
749  $this->editQuestion();
750  }
751 
755  public function removegap()
756  {
757  $this->writePostData(true);
758  $this->object->deleteAnswerText($this->gapIndex, key($_POST['cmd']['removegap_' . $this->gapIndex]));
759  $this->editQuestion();
760  }
761 
765  public function addgap()
766  {
767  $this->writePostData(true);
768  $this->object->addGapAnswer($this->gapIndex, key($_POST['cmd']['addgap_' . $this->gapIndex])+1, "");
769  $this->editQuestion();
770  }
771 
780  public function getPreview($show_question_only = false, $showInlineFeedback = false)
781  {
782  $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
783 
784  // generate the question output
785  include_once "./Services/UICore/classes/class.ilTemplate.php";
786  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
787  $output = $this->object->getClozeText();
788  foreach ($this->object->getGaps() as $gap_index => $gap) {
789  switch ($gap->getType()) {
790  case CLOZE_TEXT:
791  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", true, true, "Modules/TestQuestionPool");
792 
793  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
794  if ($gap_size > 0) {
795  $gaptemplate->setCurrentBlock('size_and_maxlength');
796  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
797  $gaptemplate->parseCurrentBlock();
798  }
799  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
800  foreach ($user_solution as $val1 => $val2) {
801  if (strcmp($val1, $gap_index) == 0) {
802  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
803  }
804  }
805  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
806  break;
807  case CLOZE_SELECT:
808  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
809  foreach ($gap->getItems($this->object->getShuffler()) as $item) {
810  $gaptemplate->setCurrentBlock("select_gap_option");
811  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
812  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
813  foreach ($user_solution as $val1 => $val2) {
814  if (strcmp($val1, $gap_index) == 0) {
815  if (strcmp($val2, $item->getOrder()) == 0) {
816  $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
817  }
818  }
819  }
820  $gaptemplate->parseCurrentBlock();
821  }
822  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
823  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
824  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
825  break;
826  case CLOZE_NUMERIC:
827  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
828  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
829  if ($gap_size > 0) {
830  $gaptemplate->setCurrentBlock('size_and_maxlength');
831  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
832  $gaptemplate->parseCurrentBlock();
833  }
834  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
835  foreach ($user_solution as $val1 => $val2) {
836  if (strcmp($val1, $gap_index) == 0) {
837  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
838  }
839  }
840  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
841  break;
842  }
843  }
844  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
845  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
846  $questionoutput = $template->get();
847  if (!$show_question_only) {
848  // get page object output
849  $questionoutput = $this->getILIASPage($questionoutput);
850  }
851  return $questionoutput;
852  }
853 
869  public function getSolutionOutput(
870  $active_id,
871  $pass = null,
872  $graphicalOutput = false,
873  $result_output = false,
874  $show_question_only = true,
875  $show_feedback = false,
876  $show_correct_solution = false,
877  $show_manual_scoring = false,
878  $show_question_text = true
879  ) {
880  // get the solution of the user for the active pass or from the last pass if allowed
881  $user_solution = array();
882  if (($active_id > 0) && (!$show_correct_solution)) {
883  // get the solutions of a user
884  $user_solution =&$this->object->getSolutionValues($active_id, $pass);
885  if (!is_array($user_solution)) {
886  $user_solution = array();
887  }
888  }
889 
890  include_once "./Services/UICore/classes/class.ilTemplate.php";
891  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution.html", true, true, "Modules/TestQuestionPool");
892  $output = $this->object->getClozeText();
893  $assClozeGapCombinationObject = new assClozeGapCombination();
894  $check_for_gap_combinations = $assClozeGapCombinationObject->loadFromDb($this->object->getId());
895 
896  foreach ($this->object->getGaps() as $gap_index => $gap) {
897  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution_gap.html", true, true, "Modules/TestQuestionPool");
898  $found = array();
899  foreach ($user_solution as $solutionarray) {
900  if ($solutionarray["value1"] == $gap_index) {
901  $found = $solutionarray;
902  }
903  }
904 
905  if ($active_id) {
906  if ($graphicalOutput) {
907  // output of ok/not ok icons for user entered solutions
908  $details = $this->object->calculateReachedPoints($active_id, $pass, true, true);
909  $check = $details[$gap_index];
910 
911  if (count($check_for_gap_combinations) != 0) {
912  $gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->object->getId());
913  $custom_user_solution = array();
914  if (array_key_exists($gap_index, $gaps_used_in_combination)) {
915  $combination_id = $gaps_used_in_combination[$gap_index];
916  foreach ($gaps_used_in_combination as $key => $value) {
917  $a = 0;
918  if ($value == $combination_id) {
919  foreach ($user_solution as $solution_key => $solution_value) {
920  if ($solution_value['value1'] == $key) {
921  $result_row = array();
922  $result_row['gap_id'] = $solution_value['value1'];
923  $result_row['value'] = $solution_value['value2'];
924  array_push($custom_user_solution, $result_row);
925  }
926  }
927  }
928  }
929  $points_array = $this->object->calculateCombinationResult($custom_user_solution);
930  $max_combination_points = $assClozeGapCombinationObject->getMaxPointsForCombination($this->object->getId(), $combination_id);
931  if ($points_array[0] == $max_combination_points) {
932  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
933  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
934  } elseif ($points_array[0] > 0) {
935  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
936  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
937  } else {
938  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
939  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
940  }
941  } else {
942  if ($check["best"]) {
943  $gaptemplate->setCurrentBlock("icon_ok");
944  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
945  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
946  $gaptemplate->parseCurrentBlock();
947  } else {
948  $gaptemplate->setCurrentBlock("icon_not_ok");
949  if ($check["positive"]) {
950  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
951  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
952  } else {
953  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
954  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
955  }
956  $gaptemplate->parseCurrentBlock();
957  }
958  }
959  } else {
960  if ($check["best"]) {
961  $gaptemplate->setCurrentBlock("icon_ok");
962  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
963  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
964  $gaptemplate->parseCurrentBlock();
965  } else {
966  $gaptemplate->setCurrentBlock("icon_not_ok");
967  if ($check["positive"]) {
968  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
969  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
970  } else {
971  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
972  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
973  }
974  $gaptemplate->parseCurrentBlock();
975  }
976  }
977  }
978  }
979  if ($result_output) {
980  $points = $this->object->getMaximumGapPoints($gap_index);
981  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
982  $gaptemplate->setCurrentBlock("result_output");
983  $gaptemplate->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
984  $gaptemplate->parseCurrentBlock();
985  }
986  $combination = null;
987  switch ($gap->getType()) {
988  case CLOZE_TEXT:
989  $solutiontext = "";
990  if (($active_id > 0) && (!$show_correct_solution)) {
991  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
992  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
993  $solutiontext .= "&nbsp;";
994  }
995  } else {
996  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
997  }
998  } else {
999  $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1000  }
1001  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1002  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1003  break;
1004  case CLOZE_SELECT:
1005  $solutiontext = "";
1006  if (($active_id > 0) && (!$show_correct_solution)) {
1007  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
1008  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1009  $solutiontext .= "&nbsp;";
1010  }
1011  } else {
1012  $item = $gap->getItem($found["value2"]);
1013  if (is_object($item)) {
1014  $solutiontext = ilUtil::prepareFormOutput($item->getAnswertext());
1015  } else {
1016  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1017  $solutiontext .= "&nbsp;";
1018  }
1019  }
1020  }
1021  } else {
1022  $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1023  }
1024  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1025  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1026  break;
1027  case CLOZE_NUMERIC:
1028  $solutiontext = "";
1029  if (($active_id > 0) && (!$show_correct_solution)) {
1030  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0)) {
1031  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1032  $solutiontext .= "&nbsp;";
1033  }
1034  } else {
1035  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
1036  }
1037  } else {
1038  $solutiontext = $this-> getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1039  }
1040  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1041  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1042  break;
1043  }
1044  }
1045 
1046  if ($show_question_text) {
1047  $template->setVariable(
1048  "QUESTIONTEXT",
1049  $this->object->prepareTextareaOutput($this->object->getQuestion(), true)
1050  );
1051  }
1052 
1053  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
1054  // generate the question output
1055  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
1056  $questionoutput = $template->get();
1057 
1058  $feedback = '';
1059  if ($show_feedback) {
1060  if (!$this->isTestPresentationContext()) {
1061  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
1062  $feedback .= strlen($fb) ? $fb : '';
1063  }
1064 
1065  $fb = $this->getSpecificFeedbackOutput($active_id, $pass);
1066  $feedback .= strlen($fb) ? $fb : '';
1067  }
1068  if (strlen($feedback)) {
1069  $cssClass = (
1070  $this->hasCorrectSolution($active_id, $pass) ?
1072  );
1073 
1074  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
1075  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
1076  }
1077 
1078  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
1079 
1080  $solutionoutput = $solutiontemplate->get();
1081 
1082  if (!$show_question_only) {
1083  // get page object output
1084  $solutionoutput = $this->getILIASPage($solutionoutput);
1085  }
1086 
1087  return $solutionoutput;
1088  }
1089 
1096  protected function getBestSolutionText($gap, $gap_index, $gap_combinations)
1097  {
1098  $combination = null;
1099  foreach ((array) $gap_combinations as $combiGapSolRow) {
1100  if ($combiGapSolRow['gap_fi'] == $gap_index) {
1101  $combination = $combiGapSolRow;
1102  break;
1103  }
1104  }
1105  $best_solution_text = ilUtil::prepareFormOutput($gap->getBestSolutionOutput(
1106  $this->object->getShuffler(),
1107  $combination
1108  ));
1109  return $best_solution_text;
1110  }
1111 
1112  public function getAnswerFeedbackOutput($active_id, $pass)
1113  {
1114  include_once "./Modules/Test/classes/class.ilObjTest.php";
1115  $manual_feedback = ilObjTest::getManualFeedback($active_id, $this->object->getId(), $pass);
1116  if (strlen($manual_feedback)) {
1117  return $manual_feedback;
1118  }
1119  $correct_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), true);
1120  $incorrect_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), false);
1121  if (strlen($correct_feedback . $incorrect_feedback)) {
1122  $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
1123  $max_points = $this->object->getMaximumPoints();
1124  if ($reached_points == $max_points) {
1125  $output .= $correct_feedback;
1126  } else {
1127  $output .= $incorrect_feedback;
1128  }
1129  }
1130  $test = new ilObjTest($this->object->active_id);
1131  return $this->object->prepareTextareaOutput($output, true);
1132  }
1133 
1134  public function getTestOutput(
1135  $active_id,
1136  // hey: prevPassSolutions - will be always available from now on
1137  $pass,
1138  // hey.
1139  $is_postponed = false,
1140  $use_post_solutions = false,
1141  $show_feedback = false
1142  ) {
1143  // get the solution of the user for the active pass or from the last pass if allowed
1144  $user_solution = array();
1145  if ($use_post_solutions !== false) {
1146  $indexedSolution = $this->object->fetchSolutionSubmit($use_post_solutions);
1147  $user_solution = $this->object->fetchValuePairsFromIndexedValues($indexedSolution);
1148  } elseif ($active_id) {
1149  // hey: prevPassSolutions - obsolete due to central check
1150  #include_once "./Modules/Test/classes/class.ilObjTest.php";
1151  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
1152  #{
1153  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
1154  #}
1155  $user_solution = $this->object->getTestOutputSolutions($active_id, $pass);
1156  // hey.
1157  if (!is_array($user_solution)) {
1158  $user_solution = array();
1159  }
1160  }
1161 
1162  // generate the question output
1163  include_once "./Services/UICore/classes/class.ilTemplate.php";
1164  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", true, true, "Modules/TestQuestionPool");
1165  $output = $this->object->getClozeText();
1166  foreach ($this->object->getGaps() as $gap_index => $gap) {
1167  switch ($gap->getType()) {
1168  case CLOZE_TEXT:
1169  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", true, true, "Modules/TestQuestionPool");
1170  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1171 
1172  if ($gap_size > 0) {
1173  $gaptemplate->setCurrentBlock('size_and_maxlength');
1174  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1175  $gaptemplate->parseCurrentBlock();
1176  }
1177 
1178  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1179  foreach ($user_solution as $solution) {
1180  if (strcmp($solution["value1"], $gap_index) == 0) {
1181  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1182  }
1183  }
1184  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1185  break;
1186  case CLOZE_SELECT:
1187  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", true, true, "Modules/TestQuestionPool");
1188  foreach ($gap->getItems($this->object->getShuffler()) as $item) {
1189  $gaptemplate->setCurrentBlock("select_gap_option");
1190  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
1191  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
1192  foreach ($user_solution as $solution) {
1193  if (strcmp($solution["value1"], $gap_index) == 0) {
1194  if (strcmp($solution["value2"], $item->getOrder()) == 0) {
1195  $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
1196  }
1197  }
1198  }
1199  $gaptemplate->parseCurrentBlock();
1200  }
1201  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
1202  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1203  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1204  break;
1205  case CLOZE_NUMERIC:
1206  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", true, true, "Modules/TestQuestionPool");
1207  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1208  if ($gap_size > 0) {
1209  $gaptemplate->setCurrentBlock('size_and_maxlength');
1210  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1211  $gaptemplate->parseCurrentBlock();
1212  }
1213 
1214  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1215  foreach ($user_solution as $solution) {
1216  if (strcmp($solution["value1"], $gap_index) == 0) {
1217  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1218  }
1219  }
1220  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1221  break;
1222  }
1223  }
1224 
1225  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
1226  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, true));
1227  $questionoutput = $template->get();
1228  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
1229  return $pageoutput;
1230  }
1231 
1239  public function setQuestionTabs()
1240  {
1241  global $rbacsystem, $ilTabs;
1242 
1243  $ilTabs->clearTargets();
1244 
1245  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
1246  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1247  $q_type = $this->object->getQuestionType();
1248 
1249  if (strlen($q_type)) {
1250  $classname = $q_type . "GUI";
1251  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
1252  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
1253  # $this->ctrl->setParameterByClass(strtolower($classname), 'prev_qid', $_REQUEST['prev_qid']);
1254  }
1255 
1256  if ($_GET["q_id"]) {
1257  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
1258  // edit page
1259  $ilTabs->addTarget(
1260  "edit_page",
1261  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
1262  array("edit", "insert", "exec_pg"),
1263  "",
1264  "",
1265  $force_active
1266  );
1267  }
1268 
1269  $this->addTab_QuestionPreview($ilTabs);
1270  }
1271 
1272  $force_active = false;
1273  $commands = $_POST["cmd"];
1274  if (is_array($commands)) {
1275  foreach ($commands as $key => $value) {
1276  if (preg_match("/^removegap_.*/", $key, $matches) ||
1277  preg_match("/^addgap_.*/", $key, $matches)
1278  ) {
1279  $force_active = true;
1280  }
1281  }
1282  }
1283  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
1284  $url = "";
1285  if ($classname) {
1286  $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
1287  }
1288  // edit question properties
1289  $ilTabs->addTarget(
1290  "edit_question",
1291  $url,
1292  array("editQuestion", "originalSyncForm", "save", "createGaps", "saveEdit"),
1293  $classname,
1294  "",
1295  $force_active
1296  );
1297  }
1298 
1299  // add tab for question feedback within common class assQuestionGUI
1300  $this->addTab_QuestionFeedback($ilTabs);
1301 
1302  // add tab for question hint within common class assQuestionGUI
1303  $this->addTab_QuestionHints($ilTabs);
1304 
1305  // add tab for question's suggested solution within common class assQuestionGUI
1306  $this->addTab_SuggestedSolution($ilTabs, $classname);
1307 
1308  // Assessment of questions sub menu entry
1309  if ($_GET["q_id"]) {
1310  $ilTabs->addTarget(
1311  "statistics",
1312  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
1313  array("assessment"),
1314  $classname,
1315  ""
1316  );
1317  }
1318 
1319  $this->addBackTab($ilTabs);
1320  }
1321 
1322  public function getSpecificFeedbackOutput($active_id, $pass)
1323  {
1324  if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists(array_values($this->object->gaps))) {
1325  return '';
1326  }
1327 
1328  global $lng;
1329 
1330  $feedback = '<table class="test_specific_feedback"><tbody>';
1331 
1332  foreach ($this->object->gaps as $index => $answer) {
1333  $caption = $lng->txt('gap') . ' ' . ($index+1) . ': ';
1334 
1335  $feedback .= '<tr><td>';
1336 
1337  $feedback .= $caption . '</td><td>';
1338  $feedback .= $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
1339  $this->object->getId(),
1340  $index
1341  ) . '</td> </tr>';
1342  }
1343  $feedback .= '</tbody></table>';
1344 
1345  return $this->object->prepareTextareaOutput($feedback, true);
1346  }
1347 
1358  {
1359  return array();
1360  }
1361 
1372  {
1373  return array();
1374  }
1375 
1384  public function getAggregatedAnswersView($relevant_answers)
1385  {
1386  $overview = array();
1387  $aggregation = array();
1388  foreach ($relevant_answers as $answer) {
1389  $overview[$answer['active_fi']][$answer['pass']][$answer['value1']] = $answer['value2'];
1390  }
1391 
1392  foreach ($overview as $active) {
1393  foreach ($active as $answer) {
1394  foreach ($answer as $option => $value) {
1395  $aggregation[$option][$value] = $aggregation[$option][$value] + 1;
1396  }
1397  }
1398  }
1399 
1400  $html = '<div>';
1401  $i = 0;
1402  foreach ($this->object->getGaps() as $gap) {
1403  if ($gap->type == CLOZE_SELECT) {
1404  $html .= '<p>Gap ' . ($i+1) . ' - SELECT</p>';
1405  $html .= '<ul>';
1406  $j = 0;
1407  foreach ($gap->getItems($this->object->getShuffler()) as $gap_item) {
1408  $aggregate = $aggregation[$i];
1409  $html .= '<li>' . ilUtil::prepareFormOutput($gap_item->getAnswerText()) . ' - ' . ($aggregate[$j] ? $aggregate[$j] : 0) . '</li>';
1410  $j++;
1411  }
1412  $html .= '</ul>';
1413  }
1414 
1415  if ($gap->type == CLOZE_TEXT) {
1416  $present_elements = array();
1417  foreach ($gap->getItems(new ilArrayElementShuffler()) as $item) {
1419  $present_elements[] = $item->getAnswertext();
1420  }
1421 
1422  $html .= '<p>Gap ' . ($i+1) . ' - TEXT</p>';
1423  $html .= '<ul>';
1424  $aggregate = (array) $aggregation[$i];
1425  foreach ($aggregate as $answer => $count) {
1426  $show_mover = '';
1427  if (in_array($answer, $present_elements)) {
1428  $show_mover = ' style="display: none;" ';
1429  }
1430 
1431  $html .= '<li>' . ilUtil::prepareFormOutput($answer) . ' - ' . $count
1432  . '&nbsp;<button class="clone_fields_add btn btn-link" ' . $show_mover . ' data-answer="' . ilUtil::prepareFormOutput($answer) . '" name="add_gap_' . $i . '_0">
1433  <span class="sr-only"></span><span class="glyphicon glyphicon-plus"></span></button>
1434  </li>';
1435  }
1436  $html .= '</ul>';
1437  }
1438 
1439  if ($gap->type == CLOZE_NUMERIC) {
1440  $html .= '<p>Gap ' . ($i+1) . ' - NUMERIC</p>';
1441  $html .= '<ul>';
1442  $j = 0;
1443  foreach ($gap->getItems($this->object->getShuffler()) as $gap_item) {
1444  $aggregate = (array) $aggregation[$i];
1445  foreach ($aggregate as $answer => $count) {
1446  $html .= '<li>' . ilUtil::prepareFormOutput($answer) . ' - ' . $count . '</li>';
1447  }
1448  $j++;
1449  }
1450  $html .= '</ul>';
1451  }
1452  $i++;
1453  $html .= '<hr />';
1454  }
1455 
1456  $html .= '</div>';
1457  return $html;
1458  }
1459 
1460  public function applyIndizesToGapText($question_text)
1461  {
1462  $parts = explode('[gap', $question_text);
1463  $i = 0;
1464  $question_text = '';
1465  foreach ($parts as $part) {
1466  if ($i == 0) {
1467  $question_text .= $part;
1468  } else {
1469  $question_text .= '[gap ' . $i . $part;
1470  }
1471  $i++;
1472  }
1473  return $question_text;
1474  }
1475 
1476  public function removeIndizesFromGapText($question_text)
1477  {
1478  $parts = preg_split('/\[gap \d*\]/', $question_text);
1479  $question_text = implode('[gap]', $parts);
1480  return $question_text;
1481  }
1482 
1487  private function populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
1488  {
1489  if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
1490  $gaptemplate->setCurrentBlock('gap_span');
1491  $gaptemplate->setVariable('SPAN_SOLUTION', $solutiontext);
1492  } elseif ($gap->getType() == CLOZE_SELECT) {
1493  $gaptemplate->setCurrentBlock('gap_select');
1494  $gaptemplate->setVariable('SELECT_SOLUTION', $solutiontext);
1495  } else {
1496  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1497 
1498  if ($gap_size > 0) {
1499  $gaptemplate->setCurrentBlock('gap_size');
1500  $gaptemplate->setVariable("GAP_SIZE", $gap_size);
1501  $gaptemplate->parseCurrentBlock();
1502  }
1503 
1504  $gaptemplate->setCurrentBlock('gap_input');
1505  $gaptemplate->setVariable('INPUT_SOLUTION', $solutiontext);
1506  }
1507 
1508 
1509  $gaptemplate->parseCurrentBlock();
1510  }
1511 }
This class represents a formula text property in a property form.
static getSelfAssessmentTags()
Get tags allowed in question tags in self assessment mode.
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms public
This class represents a duration (typical hh:mm:ss) property in a property form.
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
Class for cloze question numeric answers.
getSpecificFeedbackOutput($active_id, $pass)
Class for cloze tests.
setValue($a_value)
Set Value.
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
This class represents a selection list property in a property form.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
$template
This class represents a property form user interface.
$_GET["client_id"]
getAnswerFeedbackOutput($active_id, $pass)
const CLOZE_TEXT
Cloze question constants.
setShowHours($a_showhours)
Set Show Hours.
This class represents a section header in a property form.
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
static _getUsedHTMLTags($a_module="")
Returns an array of all allowed HTML tags for text editing.
if(!array_key_exists('StateId', $_REQUEST)) $id
setValue($a_value)
Set Value.
This class represents a checkbox property in a property form.
addItem($a_item)
Add Item (Property, SectionHeader).
populateTextGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a text gap.
setQuestionTabs()
Sets the ILIAS tabs for this question type.
$index
Definition: metadata.php:60
populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
getQuestionTemplate()
get question template
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getBestSolutionText($gap, $gap_index, $gap_combinations)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
allowDecimals($a_value)
Toggle Decimals.
This class represents a single choice wizard property in a property form.
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
This class represents a hidden form property in a property form.
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.
const CLOZE_SELECT
createGaps()
Create gaps from cloze text.
if(isset($_POST['submit'])) $form
getILIASPage($html="")
Returns the ILIAS Page around a question.
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
populateGapFormPart($form, $gapCounter)
Populates a gap form-part.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
This class represents a number property in a property form.
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
Adds the answer specific form parts to a question property form gui.
static getManualFeedback($active_id, $question_id, $pass)
Retrieves the manual feedback for a question in a test.
setValue($a_value)
Set Value.
special template class to simplify handling of ITX/PEAR
writePostData($always=false)
{}
static stripSlashesRecursive($a_data, $a_strip_html=true, $a_allow="")
Strip slashes from array and sub-arrays.
This class represents a text property in a property form.
populateGapSizeFormPart($form, $gap, $gapCounter)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
Basic GUI class for assessment questions.
removegap()
Remove a gap answer.
Create styles array
The data for the language used.
addgap()
Add a gap answer.
const ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT
constant for additional content editing mode "default"
populateNumericGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a numeric gap.
populateSelectGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a select gap.
This class represents a custom property in a property form.
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.
__construct($id=-1)
assClozeTestGUI constructor
$errors
Definition: index.php:6
Create new PHPExcel object
obj_idprivate
applyIndizesToGapText($question_text)
This class represents a text area property in a property form.
addBackTab(ilTabsGUI $ilTabs)
$i
Definition: disco.tpl.php:19
setInlineStyle($a_style)
Set inline style.
Interface ilGuiAnswerScoringAdjustable.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="")
output question page
$url
const CLOZE_NUMERIC
$gapIndex
A temporary variable to store gap indexes of ilCtrl commands in the getCommand method.
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Interface ilGuiQuestionScoringAdjustable.
setValue($a_value)
Set Value.
$key
Definition: croninfo.php:18
getPreview($show_question_only=false, $showInlineFeedback=false)
Creates a preview output of the question.
$_POST["username"]
$html
Definition: example_001.php:87
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
setRequired($a_required)
Set Required.
removeIndizesFromGapText($question_text)
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
$test
Definition: Utf8Test.php:84
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.