ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
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 
23 {
24  const OLD_CLOZE_TEST_UI = false;
25 
29  private $gapIndex;
30 
36  public function __construct($id = -1)
37  {
38  parent::__construct();
39  include_once "./Modules/TestQuestionPool/classes/class.assClozeTest.php";
40  $this->object = new assClozeTest();
41  if ($id >= 0)
42  {
43  $this->object->loadFromDb($id);
44  }
45  }
46 
47  function getCommand($cmd)
48  {
49  if (preg_match("/^(removegap|addgap)_(\d+)$/", $cmd, $matches))
50  {
51  $cmd = $matches[1];
52  $this->gapIndex = $matches[2];
53  }
54  return $cmd;
55  }
56 
65  function writePostData($always = false)
66  {
67  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
68  if (!$hasErrors)
69  {
70  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
71 
72  $cloze_text = $this->object->getHtmlQuestionContentPurifier()->purify($_POST['cloze_text']);
73 
74  $cloze_text = $this->removeIndizesFromGapText( $cloze_text );
75  $_POST['cloze_text'] = $cloze_text;
76  $this->object->setQuestion($_POST['question']);
77 
79  $this->object->setClozeText($_POST["cloze_text"]);
81  //$this->object->flushGaps();
83  $this->saveTaxonomyAssignments();
84  return 0;
85  }
86 
87  $cloze_text = $_POST['cloze_text'];
88  $cloze_text = $this->applyIndizesToGapText($cloze_text);
89  $_POST['cloze_text'] = $cloze_text;
90  return 1;
91  }
92 
94  {
95  if (is_array( $_POST['gap'] ))
96  {
97  if ( $this->ctrl->getCmd() != 'createGaps' )
98  {
99  $this->object->clearGapAnswers();
100  }
101 
102  foreach ($_POST['gap'] as $idx => $hidden)
103  {
104  $clozetype = $_POST['clozetype_' . $idx];
105 
106  $this->object->setGapType( $idx, $clozetype );
107 
108  switch($clozetype)
109  {
110  case CLOZE_TEXT:
111 
112  $this->object->setGapShuffle( $idx, 0 );
113 
114  if ($this->ctrl->getCmd() != 'createGaps')
115  {
116  if (is_array( $_POST['gap_' . $idx]['answer'] ))
117  {
118  foreach ($_POST['gap_' . $idx]['answer'] as $order => $value)
119  {
120  $this->object->addGapAnswer( $idx, $order, $value );
121  }
122  }
123  else
124  {
125  $this->object->addGapAnswer( $idx, 0, '' );
126  }
127  }
128 
129  if (is_array( $_POST['gap_' . $idx]['points'] ))
130  {
131  foreach ($_POST['gap_' . $idx]['points'] as $order => $value)
132  {
133  $this->object->setGapAnswerPoints( $idx, $order, $value );
134  }
135  }
136 
137  if (array_key_exists( 'gap_' . $idx . '_gapsize', $_POST ))
138  {
139  $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize'] );
140  }
141 
142  break;
143 
144  case CLOZE_SELECT:
145 
146  $this->object->setGapShuffle( $idx, (int)(isset($_POST["shuffle_$idx"]) && $_POST["shuffle_$idx"]) );
147 
148  if ($this->ctrl->getCmd() != 'createGaps')
149  {
150  if (is_array( $_POST['gap_' . $idx]['answer'] ))
151  {
152  foreach ($_POST['gap_' . $idx]['answer'] as $order => $value)
153  {
154  $this->object->addGapAnswer( $idx, $order, $value );
155  }
156  }
157  else
158  {
159  $this->object->addGapAnswer( $idx, 0, '' );
160  }
161  }
162 
163  if (is_array( $_POST['gap_' . $idx]['points'] ))
164  {
165  foreach ($_POST['gap_' . $idx]['points'] as $order => $value)
166  {
167  $this->object->setGapAnswerPoints( $idx, $order, $value );
168  }
169  }
170  break;
171 
172  case CLOZE_NUMERIC:
173 
174  $this->object->setGapShuffle( $idx, 0 );
175 
176  $gap = $this->object->getGap($idx);
177  if (!$gap) break;
178 
179  $this->object->getGap($idx)->clearItems();
180 
181  if (array_key_exists( 'gap_' . $idx . '_numeric', $_POST ))
182  {
183  if ($this->ctrl->getCmd() != 'createGaps')
184  {
185  $this->object->addGapAnswer(
186  $idx, 0, str_replace(",", ".", $_POST['gap_' . $idx . '_numeric'])
187  );
188  }
189 
190  $this->object->setGapAnswerLowerBound(
191  $idx, 0, str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_lower'])
192  );
193 
194  $this->object->setGapAnswerUpperBound(
195  $idx, 0, str_replace( ",", ".", $_POST['gap_' . $idx . '_numeric_upper'])
196  );
197 
198  $this->object->setGapAnswerPoints( $idx, 0, $_POST['gap_' . $idx . '_numeric_points'] );
199  }
200  else
201  {
202  if ($this->ctrl->getCmd() != 'createGaps')
203  {
204  $this->object->addGapAnswer($idx, 0, '');
205  }
206 
207  $this->object->setGapAnswerLowerBound($idx, 0, '');
208 
209  $this->object->setGapAnswerUpperBound($idx, 0, '');
210  }
211 
212  if (array_key_exists( 'gap_' . $idx . '_gapsize', $_POST ))
213  {
214  $this->object->setGapSize($idx, $order, $_POST['gap_' . $idx . '_gapsize'] );
215  }
216  break;
217  }
218  $assClozeGapCombinationObject = new assClozeGapCombination();
219  $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->object->getId());
220  if(count($_POST['gap_combination']) > 0)
221  {
222  $assClozeGapCombinationObject->saveGapCombinationToDb($this->object->getId(),ilUtil::stripSlashesRecursive($_POST['gap_combination']), ilUtil::stripSlashesRecursive($_POST['gap_combination_values']));
223  }
224  }
225  if ($this->ctrl->getCmd() != 'createGaps')
226  {
227  $this->object->updateClozeTextFromGaps();
228  }
229  }
230  }
231 
233  {
234  $this->object->setClozeText( $_POST['cloze_text'] );
235  $this->object->setTextgapRating( $_POST["textgap_rating"] );
236  $this->object->setIdenticalScoring( $_POST["identical_scoring"] );
237  $this->object->setFixedTextLength( $_POST["fixedTextLength"] );
238  }
239 
245  public function editQuestion($checkonly = FALSE)
246  {
247  $save = $this->isSaveCommand();
248  $this->getQuestionTemplate();
249 
250  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
251  $form = new ilPropertyFormGUI();
252  $form->setFormAction($this->ctrl->getFormAction($this));
253  $form->setTitle($this->outQuestionType());
254  $form->setMultipart(FALSE);
255  $form->setTableWidth("100%");
256  $form->setId("assclozetest");
257 
258  // title, author, description, question, working time (assessment mode)
259  $this->addBasicQuestionFormProperties($form);
260  $this->populateQuestionSpecificFormPart( $form );
261  $this->populateAnswerSpecificFormPart( $form );
262  $this->populateTaxonomyFormSection($form);
263 
264  $this->addQuestionFormCommandButtons($form);
265 
266  $errors = false;
267 
268  if ($save)
269  {
270  $form->setValuesByPost();
271  $errors = !$form->checkInput();
272  $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we
273  // need this if we don't want to have duplication of backslashes
274  if ($errors) $checkonly = false;
275  }
276 
277  if (!$checkonly) $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
278  return $errors;
279  }
280 
282  {
283  // title
284  $title = new ilTextInputGUI($this->lng->txt("title"), "title");
285  $title->setMaxLength(100);
286  $title->setValue($this->object->getTitle());
287  $title->setRequired(TRUE);
288  $form->addItem($title);
289 
290  if (!$this->object->getSelfAssessmentEditingMode())
291  {
292  // author
293  $author = new ilTextInputGUI($this->lng->txt("author"), "author");
294  $author->setValue($this->object->getAuthor());
295  $author->setRequired(TRUE);
296  $form->addItem($author);
297 
298  // description
299  $description = new ilTextInputGUI($this->lng->txt("description"), "comment");
300  $description->setValue($this->object->getComment());
301  $description->setRequired(FALSE);
302  $form->addItem($description);
303  }
304  else
305  {
306  // author as hidden field
307  $hi = new ilHiddenInputGUI("author");
308  $author = ilUtil::prepareFormOutput($this->object->getAuthor());
309  if (trim($author) == "")
310  {
311  $author = "-";
312  }
313  $hi->setValue($author);
314  $form->addItem($hi);
315 
316  }
317 
318  // questiontext
319  $question = new ilTextAreaInputGUI($this->lng->txt("question"), "question");
320  $question->setValue($this->object->prepareTextareaOutput($this->object->getQuestion()));
321  $question->setRequired(TRUE);
322  $question->setRows(10);
323  $question->setCols(80);
324  if (!$this->object->getSelfAssessmentEditingMode())
325  {
326  if( $this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT )
327  {
328  $question->setUseRte(TRUE);
329  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
330  $question->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
331  $question->addPlugin("latex");
332  $question->addButton("latex");
333  $question->addButton("pastelatex");
334  $question->setRTESupport($this->object->getId(), "qpl", "assessment");
335  }
336  }
337  else
338  {
339  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
341  $question->setUseTagsForRteOnly(false);
342  }
343  $form->addItem($question);
344 
345 // $tpl = new ilTemplate("tpl.il_as_qpl_cloze_gap_button_code.html", TRUE, TRUE, "Modules/TestQuestionPool");
346 // $tpl->setVariable('INSERT_GAP', $this->lng->txt('insert_gap'));
347 // $tpl->setVariable('CREATE_GAPS', $this->lng->txt('create_gaps'));
348 // $tpl->parseCurrentBlock();
349 // $button = new ilCustomInputGUI('&nbsp;','');
350 // $button->setHtml($tpl->get());
351 // $form->addItem($button);
352 
353  if (!$this->object->getSelfAssessmentEditingMode())
354  {
355  // duration
356  $duration = new ilDurationInputGUI($this->lng->txt("working_time"), "Estimated");
357  $duration->setShowHours(TRUE);
358  $duration->setShowMinutes(TRUE);
359  $duration->setShowSeconds(TRUE);
360  $ewt = $this->object->getEstimatedWorkingTime();
361  $duration->setHours($ewt["h"]);
362  $duration->setMinutes($ewt["m"]);
363  $duration->setSeconds($ewt["s"]);
364  $duration->setRequired(FALSE);
365  $form->addItem($duration);
366  }
367  else
368  {
369  // number of tries
370  if (strlen($this->object->getNrOfTries()))
371  {
372  $nr_tries = $this->object->getNrOfTries();
373  }
374  else
375  {
376  $nr_tries = $this->object->getDefaultNrOfTries();
377  }
378  /*if ($nr_tries <= 0)
379  {
380  $nr_tries = 1;
381  }*/
382 
383  if ($nr_tries < 0)
384  {
385  $nr_tries = 0;
386  }
387 
388  $ni = new ilNumberInputGUI($this->lng->txt("qst_nr_of_tries"), "nr_of_tries");
389  $ni->setValue($nr_tries);
390  //$ni->setMinValue(1);
391  $ni->setMinValue(0);
392  $ni->setSize(5);
393  $ni->setMaxLength(5);
394  $ni->setRequired(true);
395  $form->addItem($ni);
396  }
397  }
398 
400  {
401  // cloze text
402  $cloze_text = new ilTextAreaInputGUI($this->lng->txt("cloze_text"), 'cloze_text');
403  $cloze_text->setRequired(true);
404  $cloze_text->setValue($this->applyIndizesToGapText($this->object->getClozeText()));
405  $cloze_text->setInfo($this->lng->txt("close_text_hint"));
406  $cloze_text->setRows( 10 );
407  $cloze_text->setCols( 80 );
408  if (!$this->object->getSelfAssessmentEditingMode())
409  {
410  if( $this->object->getAdditionalContentEditingMode() == assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT )
411  {
412  $cloze_text->setUseRte(TRUE);
413  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
414  $cloze_text->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
415  $cloze_text->addPlugin("latex");
416  $cloze_text->addButton("latex");
417  $cloze_text->addButton("pastelatex");
418  }
419  }
420  else
421  {
422  require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssSelfAssessmentQuestionFormatter.php';
424  $cloze_text->setUseTagsForRteOnly(false);
425  }
426  $cloze_text->setRTESupport($this->object->getId(), "qpl", "assessment");
427  $form->addItem($cloze_text);
428 
429  $tpl = new ilTemplate("tpl.il_as_qpl_cloze_gap_button_code.html", TRUE, TRUE, "Modules/TestQuestionPool");
430  $tpl->setVariable('INSERT_GAP', $this->lng->txt('insert_gap'));
431  $tpl->setVariable('CREATE_GAPS', $this->lng->txt('create_gaps'));
432  $tpl->parseCurrentBlock();
433  $button = new ilCustomInputGUI('&nbsp;','');
434  $button->setHtml($tpl->get());
435  $form->addItem($button);
436 
437  // text rating
438  if (!$this->object->getSelfAssessmentEditingMode())
439  {
440  $textrating = new ilSelectInputGUI($this->lng->txt( "text_rating" ), "textgap_rating");
441  $text_options = array(
442  "ci" => $this->lng->txt( "cloze_textgap_case_insensitive" ),
443  "cs" => $this->lng->txt( "cloze_textgap_case_sensitive" ),
444  "l1" => sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "1" ),
445  "l2" => sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "2" ),
446  "l3" => sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "3" ),
447  "l4" => sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "4" ),
448  "l5" => sprintf( $this->lng->txt( "cloze_textgap_levenshtein_of" ), "5" )
449  );
450  $textrating->setOptions( $text_options );
451  $textrating->setValue( $this->object->getTextgapRating() );
452  $form->addItem( $textrating );
453 
454  // text field length
455  $fixedTextLength = new ilNumberInputGUI($this->lng->txt( "cloze_fixed_textlength" ), "fixedTextLength");
456  $ftl = $this->object->getFixedTextLength();
457 
458  $fixedTextLength->setValue( $ftl > 0 ? $ftl : '' );
459  $fixedTextLength->setMinValue( 0 );
460  $fixedTextLength->setSize( 3 );
461  $fixedTextLength->setMaxLength( 6 );
462  $fixedTextLength->setInfo( $this->lng->txt( 'cloze_fixed_textlength_description' ) );
463  $fixedTextLength->setRequired( false );
464  $form->addItem( $fixedTextLength );
465 
466  // identical scoring
467  $identical_scoring = new ilCheckboxInputGUI($this->lng->txt( "identical_scoring" ), "identical_scoring");
468  $identical_scoring->setValue( 1 );
469  $identical_scoring->setChecked( $this->object->getIdenticalScoring() );
470  $identical_scoring->setInfo( $this->lng->txt( 'identical_scoring_desc' ) );
471  $identical_scoring->setRequired( FALSE );
472  $form->addItem( $identical_scoring );
473  }
474  return $form;
475  }
476 
478  {
479  if(self::OLD_CLOZE_TEST_UI)
480  {
481  for ($gapCounter = 0; $gapCounter < $this->object->getGapCount(); $gapCounter++)
482  {
483  $this->populateGapFormPart( $form, $gapCounter );
484  }
485  return $form;
486  }
487  else
488  {
489  require_once 'Modules/TestQuestionPool/classes/Form/class.ilClozeGapInputBuilderGUI.php';
490  $json=$this->populateJSON();
491  $assClozeGapCombinationObject = new assClozeGapCombination();
492  $combination_exists = $assClozeGapCombinationObject->combinationExistsForQid($this->object->id);
493  if($combination_exists)
494  {
495  $combinations = $assClozeGapCombinationObject->loadFromDb($this->object->id);
496  }
497  $new_builder = new ilClozeGapInputBuilderGUI();
499  $form->addItem($header);
500  $new_builder->setValueByArray($json);
501  $new_builder->setValueCombinationFromDb($combinations);
502  $form->addItem($new_builder);
503  return $form;
504  }
505  }
506 
507  protected function populateJSON()
508  {
509  $gap = $this->object->getGaps();
510  $array = array();
511  if ($gap == null)
512  {
513  return $array;
514  }
515  $translate_type=array('text','select','numeric');
516  $i = 0;
517  foreach ($gap as $content)
518  {
519  $shuffle=false;
520  $value=$content->getItemsRaw();
521  $items=array();
522  for($j=0;$j<count($value);$j++)
523  {
524  if($content->getType()==2)
525  {
526  $items[$j] = array(
527  'answer' => $value[$j]->getAnswerText(),
528  'lower' => $value[$j]->getLowerBound(),
529  'upper' => $value[$j]->getUpperBound(),
530  'points' => $value[$j]->getPoints(),
531  'error' => false
532  );
533  }
534  else
535  {
536  $items[$j] = array(
537  'answer' => $value[$j]->getAnswerText(),
538  'points' => $value[$j]->getPoints(),
539  'error' => false
540  );
541 
542  if($content->getType()==1)
543  {
544  $shuffle=$content->getShuffle();
545  }
546  }
547  }
548  $answers[$i]=array(
549  'type' => $translate_type[$content->getType()] ,
550  'values' => $items ,
551  'shuffle' => $shuffle,
552  'text_field_length' => $content->getGapSize() > 0 ? $content->getGapSize() : '',
553  'used_in_gap_combination' => true);
554  $i++;
555  }
556  return $answers;
557  }
569  protected function populateGapFormPart($form, $gapCounter)
570  {
571  $gap = $this->object->getGap( $gapCounter );
572 
573  if ($gap == null)
574  {
575  return $form;
576  }
577 
579  $header->setTitle( $this->lng->txt( "gap" ) . " " . ($gapCounter + 1) );
580  $form->addItem( $header );
581 
582  $gapcounter = new ilHiddenInputGUI("gap[$gapCounter]");
583  $gapcounter->setValue( $gapCounter );
584  $form->addItem( $gapcounter );
585 
586  $gaptype = new ilSelectInputGUI($this->lng->txt( 'type' ), "clozetype_$gapCounter");
587  $options = array(
588  0 => $this->lng->txt( "text_gap" ),
589  1 => $this->lng->txt( "select_gap" ),
590  2 => $this->lng->txt( "numeric_gap" )
591  );
592  $gaptype->setOptions( $options );
593  $gaptype->setValue( $gap->getType() );
594  $form->addItem( $gaptype );
595 
596  if ($gap->getType() == CLOZE_TEXT)
597  {
598  $this->populateGapSizeFormPart($form, $gap, $gapCounter);
599 
600  if (count( $gap->getItemsRaw() ) == 0)
601  $gap->addItem( new assAnswerCloze("", 0, 0) );
602  $this->populateTextGapFormPart( $form, $gap, $gapCounter );
603  }
604  else if ($gap->getType() == CLOZE_SELECT)
605  {
606  if (count( $gap->getItemsRaw() ) == 0)
607  $gap->addItem( new assAnswerCloze("", 0, 0) );
608  $this->populateSelectGapFormPart( $form, $gap, $gapCounter );
609  }
610  else if ($gap->getType() == CLOZE_NUMERIC)
611  {
612  $this->populateGapSizeFormPart($form, $gap, $gapCounter);
613 
614  if (count( $gap->getItemsRaw() ) == 0)
615  $gap->addItem( new assAnswerCloze("", 0, 0) );
616  foreach ($gap->getItemsRaw() as $item)
617  {
618  $this->populateNumericGapFormPart( $form, $item, $gapCounter );
619  }
620  }
621  return $form;
622  }
623 
629  protected function populateGapSizeFormPart($form, $gap, $gapCounter)
630  {
631  $gapSizeFormItem = new ilNumberInputGUI($this->lng->txt('cloze_fixed_textlength'), "gap_".$gapCounter.'_gapsize');
632 
633  $gapSizeFormItem->allowDecimals(false);
634  $gapSizeFormItem->setMinValue(0);
635  $gapSizeFormItem->setSize( 3 );
636  $gapSizeFormItem->setMaxLength( 6 );
637  $gapSizeFormItem->setInfo($this->lng->txt('cloze_gap_size_info'));
638  $gapSizeFormItem->setValue($gap->getGapSize());
639  $form->addItem($gapSizeFormItem);
640 
641  return $form;
642  }
643 
656  protected function populateSelectGapFormPart($form, $gap, $gapCounter)
657  {
658  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
659  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
660  $values = new ilAnswerWizardInputGUI($this->lng->txt( "values" ), "gap_" . $gapCounter . "");
661  $values->setRequired( true );
662  $values->setQuestionObject( $this->object );
663  $values->setSingleline( true );
664  $values->setAllowMove( false );
665 
666  $values->setValues( $gap->getItemsRaw() );
667  $form->addItem( $values );
668 
669  // shuffle
670  $shuffle = new ilCheckboxInputGUI($this->lng->txt( "shuffle_answers" ), "shuffle_" . $gapCounter . "");
671  $shuffle->setValue( 1 );
672  $shuffle->setChecked( $gap->getShuffle() );
673  $shuffle->setRequired( FALSE );
674  $form->addItem( $shuffle );
675  return $form;
676  }
677 
689  protected function populateTextGapFormPart($form, $gap, $gapCounter)
690  {
691  // Choices
692  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
693  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
694  $values = new ilAnswerWizardInputGUI($this->lng->txt( "values" ), "gap_" . $gapCounter . "");
695  $values->setRequired( true );
696  $values->setQuestionObject( $this->object );
697  $values->setSingleline( true );
698  $values->setAllowMove( false );
699  $values->setValues( $gap->getItemsRaw() );
700  $form->addItem( $values );
701 
702  if( $this->object->getFixedTextLength() > 0 )
703  {
704  $values->setSize( $this->object->getFixedTextLength() );
705  $values->setMaxLength( $this->object->getFixedTextLength() );
706  }
707 
708  return $form;
709  }
710 
722  protected function populateNumericGapFormPart($form, $gap, $gapCounter)
723  {
724  // #8944: the js-based ouput in self-assessment cannot support formulas
725  if (!$this->object->getSelfAssessmentEditingMode())
726  {
727  $value = new ilFormulaInputGUI($this->lng->txt( 'value' ), "gap_" . $gapCounter . "_numeric");
728  $value->setInlineStyle( 'text-align: right;' );
729 
730  $lowerbound = new ilFormulaInputGUI($this->lng->txt( 'range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
731  $lowerbound->setInlineStyle( 'text-align: right;' );
732 
733  $upperbound = new ilFormulaInputGUI($this->lng->txt( 'range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
734  $upperbound->setInlineStyle( 'text-align: right;' );
735  }
736  else
737  {
738  $value = new ilNumberInputGUI($this->lng->txt( 'value' ), "gap_" . $gapCounter . "_numeric");
739  $value->allowDecimals( true );
740 
741  $lowerbound = new ilNumberInputGUI($this->lng->txt( 'range_lower_limit'), "gap_" . $gapCounter . "_numeric_lower");
742  $lowerbound->allowDecimals( true );
743 
744  $upperbound = new ilNumberInputGUI($this->lng->txt( 'range_upper_limit'), "gap_" . $gapCounter . "_numeric_upper");
745  $upperbound->allowDecimals( true );
746  }
747 
748  $value->setSize( 10 );
749  $value->setValue( ilUtil::prepareFormOutput( $gap->getAnswertext() ) );
750  $value->setRequired( true );
751  $form->addItem( $value );
752 
753  $lowerbound->setSize( 10 );
754  $lowerbound->setRequired( true );
755  $lowerbound->setValue( ilUtil::prepareFormOutput( $gap->getLowerBound() ) );
756  $form->addItem( $lowerbound );
757 
758  $upperbound->setSize( 10 );
759  $upperbound->setRequired( true );
760  $upperbound->setValue( ilUtil::prepareFormOutput( $gap->getUpperBound() ) );
761  $form->addItem( $upperbound );
762 
763  if( $this->object->getFixedTextLength() > 0 )
764  {
765  $value->setSize( $this->object->getFixedTextLength() );
766  $value->setMaxLength( $this->object->getFixedTextLength() );
767  $lowerbound->setSize( $this->object->getFixedTextLength() );
768  $lowerbound->setMaxLength( $this->object->getFixedTextLength() );
769  $upperbound->setSize( $this->object->getFixedTextLength() );
770  $upperbound->setMaxLength( $this->object->getFixedTextLength() );
771  }
772 
773  $points = new ilNumberInputGUI($this->lng->txt( 'points' ), "gap_" . $gapCounter . "_numeric_points");
774  $points->allowDecimals(true);
775  $points->setSize( 3 );
776  $points->setRequired( true );
777  $points->setValue( ilUtil::prepareFormOutput( $gap->getPoints() ) );
778  $form->addItem( $points );
779  return $form;
780  }
781 
785  public function createGaps()
786  {
787  $this->writePostData(true);
788  $this->object->saveToDb();
789  $this->editQuestion();
790  }
791 
795  function removegap()
796  {
797  $this->writePostData(true);
798  $this->object->deleteAnswerText($this->gapIndex, key($_POST['cmd']['removegap_' . $this->gapIndex]));
799  $this->editQuestion();
800  }
801 
805  function addgap()
806  {
807  $this->writePostData(true);
808  $this->object->addGapAnswer($this->gapIndex, key($_POST['cmd']['addgap_' . $this->gapIndex])+1, "");
809  $this->editQuestion();
810  }
811 
820  function getPreview($show_question_only = FALSE, $showInlineFeedback = false)
821  {
822  $user_solution = is_object($this->getPreviewSession()) ? (array)$this->getPreviewSession()->getParticipantsSolution() : array();
823 
824  // generate the question output
825  include_once "./Services/UICore/classes/class.ilTemplate.php";
826  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
827  $output = $this->object->getClozeText();
828  foreach ($this->object->getGaps() as $gap_index => $gap)
829  {
830  switch ($gap->getType())
831  {
832  case CLOZE_TEXT:
833  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", TRUE, TRUE, "Modules/TestQuestionPool");
834 
835  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
836  if($gap_size > 0)
837  {
838  $gaptemplate->setCurrentBlock('size_and_maxlength');
839  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
840  $gaptemplate->parseCurrentBlock();
841  }
842  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
843  foreach ($user_solution as $val1 => $val2)
844  {
845  if (strcmp($val1, $gap_index) == 0)
846  {
847  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
848  }
849  }
850  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
851  break;
852  case CLOZE_SELECT:
853  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", TRUE, TRUE, "Modules/TestQuestionPool");
854  foreach ($gap->getItems($this->object->getShuffler()) as $item)
855  {
856  $gaptemplate->setCurrentBlock("select_gap_option");
857  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
858  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
859  foreach ($user_solution as $val1 => $val2)
860  {
861  if (strcmp($val1, $gap_index) == 0)
862  {
863  if (strcmp($val2, $item->getOrder()) == 0)
864  {
865  $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
866  }
867  }
868  }
869  $gaptemplate->parseCurrentBlock();
870  }
871  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
872  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
873  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
874  break;
875  case CLOZE_NUMERIC:
876  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", TRUE, TRUE, "Modules/TestQuestionPool");
877  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
878  if($gap_size > 0)
879  {
880  $gaptemplate->setCurrentBlock('size_and_maxlength');
881  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
882  $gaptemplate->parseCurrentBlock();
883  }
884  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
885  foreach ($user_solution as $val1 => $val2)
886  {
887  if (strcmp($val1, $gap_index) == 0)
888  {
889  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($val2) . "\"");
890  }
891  }
892  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
893  break;
894  }
895  }
896  $template->setVariable("QUESTIONTEXT",$this->object->prepareTextareaOutput( $this->object->getQuestion(), true));
897  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, TRUE));
898  $questionoutput = $template->get();
899  if (!$show_question_only)
900  {
901  // get page object output
902  $questionoutput = $this->getILIASPage($questionoutput);
903  }
904  return $questionoutput;
905  }
906 
923  $active_id,
924  $pass = NULL,
925  $graphicalOutput = FALSE,
926  $result_output = FALSE,
927  $show_question_only = TRUE,
928  $show_feedback = FALSE,
929  $show_correct_solution = FALSE,
930  $show_manual_scoring = FALSE,
931  $show_question_text = TRUE
932  )
933  {
934  // get the solution of the user for the active pass or from the last pass if allowed
935  $user_solution = array();
936  if (($active_id > 0) && (!$show_correct_solution))
937  {
938  // get the solutions of a user
939  $user_solution =& $this->object->getSolutionValues($active_id, $pass);
940  if(!is_array($user_solution))
941  {
942  $user_solution = array();
943  }
944  }
945 
946  include_once "./Services/UICore/classes/class.ilTemplate.php";
947  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution.html", TRUE, TRUE, "Modules/TestQuestionPool");
948  $output = $this->object->getClozeText();
949  foreach ($this->object->getGaps() as $gap_index => $gap)
950  {
951  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution_gap.html", TRUE, TRUE, "Modules/TestQuestionPool");
952  $found = array();
953  foreach ($user_solution as $solutionarray)
954  {
955  if ($solutionarray["value1"] == $gap_index) $found = $solutionarray;
956  }
957 
958  if ($active_id)
959  {
960  if ($graphicalOutput)
961  {
962  // output of ok/not ok icons for user entered solutions
963  $details = $this->object->calculateReachedPoints($active_id, $pass, true, TRUE);
964  $check = $details[$gap_index];
965 
966  $assClozeGapCombinationObject = new assClozeGapCombination();
967  $check_for_gap_combinations = $assClozeGapCombinationObject->loadFromDb($this->object->getId());
968  if(count($check_for_gap_combinations) != 0)
969  {
970  $gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->object->getId());
971  $custom_user_solution = array();
972  if(array_key_exists($gap_index, $gaps_used_in_combination))
973  {
974  $combination_id = $gaps_used_in_combination[$gap_index];
975  foreach($gaps_used_in_combination as $key => $value)
976  {
977  $a = 0;
978  if($value == $combination_id)
979  {
980 
981  foreach($user_solution as $solution_key => $solution_value)
982  {
983  if($solution_value['value1'] == $key)
984  {
985  $result_row = array();
986  $result_row['gap_id'] = $solution_value['value1'];
987  $result_row['value'] = $solution_value['value2'];
988  array_push($custom_user_solution, $result_row);
989  }
990  }
991  }
992  }
993  $points_array = $this->object->calculateCombinationResult($custom_user_solution);
994  $max_combination_points = $assClozeGapCombinationObject->getMaxPointsForCombination($this->object->getId(), $combination_id);
995  if($points_array[0] == $max_combination_points)
996  {
997  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
998  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
999  }
1000  else if($points_array[0] > 0)
1001  {
1002  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
1003  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
1004  }
1005  else
1006  {
1007  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
1008  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
1009  }
1010 
1011  }
1012  else
1013  {
1014  if ($check["best"])
1015  {
1016  $gaptemplate->setCurrentBlock("icon_ok");
1017  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
1018  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
1019  $gaptemplate->parseCurrentBlock();
1020  }
1021  else
1022  {
1023  $gaptemplate->setCurrentBlock("icon_not_ok");
1024  if ($check["positive"])
1025  {
1026  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
1027  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
1028  }
1029  else
1030  {
1031  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
1032  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
1033  }
1034  $gaptemplate->parseCurrentBlock();
1035  }
1036  }
1037  }
1038  else
1039  {
1040  if ($check["best"])
1041  {
1042  $gaptemplate->setCurrentBlock("icon_ok");
1043  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
1044  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
1045  $gaptemplate->parseCurrentBlock();
1046  }
1047  else
1048  {
1049  $gaptemplate->setCurrentBlock("icon_not_ok");
1050  if ($check["positive"])
1051  {
1052  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.svg"));
1053  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
1054  }
1055  else
1056  {
1057  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
1058  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
1059  }
1060  $gaptemplate->parseCurrentBlock();
1061  }
1062  }
1063 
1064  }
1065  }
1066  if ($result_output)
1067  {
1068  $points = $this->object->getMaximumGapPoints($gap_index);
1069  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
1070  $gaptemplate->setCurrentBlock("result_output");
1071  $gaptemplate->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
1072  $gaptemplate->parseCurrentBlock();
1073  }
1074  switch ($gap->getType())
1075  {
1076  case CLOZE_TEXT:
1077  $solutiontext = "";
1078  if (($active_id > 0) && (!$show_correct_solution))
1079  {
1080  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
1081  {
1082  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
1083  {
1084  $solutiontext .= "&nbsp;";
1085  }
1086  }
1087  else
1088  {
1089  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
1090  }
1091  }
1092  else
1093  {
1094  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput(
1095  $this->object->getShuffler()
1096  ));
1097  }
1098  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1099  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1100  break;
1101  case CLOZE_SELECT:
1102  $solutiontext = "";
1103  if (($active_id > 0) && (!$show_correct_solution))
1104  {
1105  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
1106  {
1107  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
1108  {
1109  $solutiontext .= "&nbsp;";
1110  }
1111  }
1112  else
1113  {
1114  $item = $gap->getItem($found["value2"]);
1115  if (is_object($item))
1116  {
1117  $solutiontext = ilUtil::prepareFormOutput($item->getAnswertext());
1118  }
1119  else
1120  {
1121  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
1122  {
1123  $solutiontext .= "&nbsp;";
1124  }
1125  }
1126  }
1127  }
1128  else
1129  {
1130  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput(
1131  $this->object->getShuffler()
1132  ));
1133  }
1134  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1135  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1136  break;
1137  case CLOZE_NUMERIC:
1138  $solutiontext = "";
1139  if (($active_id > 0) && (!$show_correct_solution))
1140  {
1141  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
1142  {
1143  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
1144  {
1145  $solutiontext .= "&nbsp;";
1146  }
1147  }
1148  else
1149  {
1150  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
1151  }
1152  }
1153  else
1154  {
1155  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput(
1156  $this->object->getShuffler()
1157  ));
1158  }
1159  $this->populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext);
1160  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1161  break;
1162  }
1163  }
1164 
1165  if ($show_question_text)
1166  {
1167  $template->setVariable(
1168  "QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true)
1169  );
1170  }
1171 
1172  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, TRUE));
1173  // generate the question output
1174  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html",TRUE, TRUE, "Modules/TestQuestionPool");
1175  $questionoutput = $template->get();
1176 
1177  $feedback = '';
1178  if($show_feedback)
1179  {
1180  if( !$this->isTestPresentationContext() )
1181  {
1182  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
1183  $feedback .= strlen($fb) ? $fb : '';
1184  }
1185 
1186  $fb = $this->getSpecificFeedbackOutput($active_id, $pass);
1187  $feedback .= strlen($fb) ? $fb : '';
1188  }
1189  if (strlen($feedback))
1190  {
1191  $cssClass = ( $this->hasCorrectSolution($active_id, $pass) ?
1193  );
1194 
1195  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
1196  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput( $feedback, true ));
1197  }
1198 
1199  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
1200 
1201  $solutionoutput = $solutiontemplate->get();
1202 
1203  if (!$show_question_only)
1204  {
1205  // get page object output
1206  $solutionoutput = $this->getILIASPage($solutionoutput);
1207  }
1208 
1209  return $solutionoutput;
1210  }
1211 
1212  public function getAnswerFeedbackOutput($active_id, $pass)
1213  {
1214  include_once "./Modules/Test/classes/class.ilObjTest.php";
1215  $manual_feedback = ilObjTest::getManualFeedback($active_id, $this->object->getId(), $pass);
1216  if (strlen($manual_feedback))
1217  {
1218  return $manual_feedback;
1219  }
1220  $useAuthorizedSolution = $this->isLastSolutionSubmitAuthorized($active_id, $pass);
1221  $correct_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), true);
1222  $incorrect_feedback = $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), false);
1223  if (strlen($correct_feedback.$incorrect_feedback))
1224  {
1225  $reached_points = $this->object->calculateReachedPoints($active_id, $pass, (bool)$useAuthorizedSolution);
1226  $max_points = $this->object->getMaximumPoints();
1227  if ($reached_points == $max_points)
1228  {
1229  $output .= $correct_feedback;
1230  }
1231  else
1232  {
1233  $output .= $incorrect_feedback;
1234  }
1235  }
1236  $test = new ilObjTest($this->object->active_id);
1237  return $this->object->prepareTextareaOutput($output, TRUE);
1238  }
1239 
1240  function getTestOutput(
1241  $active_id,
1242  // hey: prevPassSolutions - will be always available from now on
1243  $pass,
1244  // hey.
1245  $is_postponed = FALSE,
1246  $use_post_solutions = FALSE,
1247  $show_feedback = FALSE
1248  )
1249  {
1250  // get the solution of the user for the active pass or from the last pass if allowed
1251  $user_solution = array();
1252  if ($active_id)
1253  {
1254  // hey: prevPassSolutions - obsolete due to central check
1255  #include_once "./Modules/Test/classes/class.ilObjTest.php";
1256  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
1257  #{
1258  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
1259  #}
1260  $user_solution = $this->getTestOutputSolutions($active_id, $pass);
1261  // hey.
1262  if (!is_array($user_solution))
1263  {
1264  $user_solution = array();
1265  }
1266  }
1267 
1268  // generate the question output
1269  include_once "./Services/UICore/classes/class.ilTemplate.php";
1270  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
1271  $output = $this->object->getClozeText();
1272  foreach ($this->object->getGaps() as $gap_index => $gap)
1273  {
1274  switch ($gap->getType())
1275  {
1276  case CLOZE_TEXT:
1277  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", TRUE, TRUE, "Modules/TestQuestionPool");
1278  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1279 
1280  if($gap_size > 0)
1281  {
1282  $gaptemplate->setCurrentBlock('size_and_maxlength');
1283  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1284  $gaptemplate->parseCurrentBlock();
1285  }
1286 
1287  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1288  foreach ($user_solution as $solution)
1289  {
1290  if (strcmp($solution["value1"], $gap_index) == 0)
1291  {
1292  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1293  }
1294  }
1295  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1296  break;
1297  case CLOZE_SELECT:
1298  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", TRUE, TRUE, "Modules/TestQuestionPool");
1299  foreach ($gap->getItems($this->object->getShuffler()) as $item)
1300  {
1301  $gaptemplate->setCurrentBlock("select_gap_option");
1302  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
1303  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
1304  foreach ($user_solution as $solution)
1305  {
1306  if (strcmp($solution["value1"], $gap_index) == 0)
1307  {
1308  if (strcmp($solution["value2"], $item->getOrder()) == 0)
1309  {
1310  $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
1311  }
1312  }
1313  }
1314  $gaptemplate->parseCurrentBlock();
1315  }
1316  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
1317  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1318  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1319  break;
1320  case CLOZE_NUMERIC:
1321  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", TRUE, TRUE, "Modules/TestQuestionPool");
1322  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1323  if($gap_size > 0)
1324  {
1325  $gaptemplate->setCurrentBlock('size_and_maxlength');
1326  $gaptemplate->setVariable("TEXT_GAP_SIZE", $gap_size);
1327  $gaptemplate->parseCurrentBlock();
1328  }
1329 
1330  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
1331  foreach ($user_solution as $solution)
1332  {
1333  if (strcmp($solution["value1"], $gap_index) == 0)
1334  {
1335  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
1336  }
1337  }
1338  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
1339  break;
1340  }
1341  }
1342 
1343  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), true));
1344  $template->setVariable("CLOZETEXT", $this->object->prepareTextareaOutput($output, TRUE));
1345  $questionoutput = $template->get();
1346  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
1347  return $pageoutput;
1348  }
1349 
1357  public function setQuestionTabs()
1358  {
1359  global $rbacsystem, $ilTabs;
1360 
1361  $ilTabs->clearTargets();
1362 
1363  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
1364  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1365  $q_type = $this->object->getQuestionType();
1366 
1367  if (strlen($q_type))
1368  {
1369  $classname = $q_type . "GUI";
1370  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
1371  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
1372 # $this->ctrl->setParameterByClass(strtolower($classname), 'prev_qid', $_REQUEST['prev_qid']);
1373  }
1374 
1375  if ($_GET["q_id"])
1376  {
1377  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
1378  {
1379  // edit page
1380  $ilTabs->addTarget("edit_page",
1381  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
1382  array("edit", "insert", "exec_pg"),
1383  "", "", $force_active);
1384  }
1385 
1386  $this->addTab_QuestionPreview($ilTabs);
1387  }
1388 
1389  $force_active = false;
1390  $commands = $_POST["cmd"];
1391  if (is_array($commands))
1392  {
1393  foreach ($commands as $key => $value)
1394  {
1395  if (preg_match("/^removegap_.*/", $key, $matches) ||
1396  preg_match("/^addgap_.*/", $key, $matches)
1397  )
1398  {
1399  $force_active = true;
1400  }
1401  }
1402  }
1403  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
1404  {
1405  $url = "";
1406  if ($classname) $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
1407  // edit question properties
1408  $ilTabs->addTarget("edit_question",
1409  $url,
1410  array("editQuestion", "originalSyncForm", "save", "createGaps", "saveEdit"),
1411  $classname, "", $force_active);
1412  }
1413 
1414  // add tab for question feedback within common class assQuestionGUI
1415  $this->addTab_QuestionFeedback($ilTabs);
1416 
1417  // add tab for question hint within common class assQuestionGUI
1418  $this->addTab_QuestionHints($ilTabs);
1419 
1420  // add tab for question's suggested solution within common class assQuestionGUI
1421  $this->addTab_SuggestedSolution($ilTabs, $classname);
1422 
1423  // Assessment of questions sub menu entry
1424  if ($_GET["q_id"])
1425  {
1426  $ilTabs->addTarget("statistics",
1427  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
1428  array("assessment"),
1429  $classname, "");
1430  }
1431 
1432  $this->addBackTab($ilTabs);
1433  }
1434 
1435  function getSpecificFeedbackOutput($active_id, $pass)
1436  {
1437  if( !$this->object->feedbackOBJ->specificAnswerFeedbackExists(array_values($this->object->gaps)) )
1438  {
1439  return '';
1440  }
1441 
1442  global $lng;
1443 
1444  $feedback = '<table class="test_specific_feedback"><tbody>';
1445 
1446  foreach ($this->object->gaps as $index => $answer)
1447  {
1448  $caption = $lng->txt('gap').' '.($index+1) .': ';
1449 
1450  $feedback .= '<tr><td>';
1451 
1452  $feedback .= $caption .'</td><td>';
1453  $feedback .= $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
1454  $this->object->getId(), $index
1455  ) . '</td> </tr>';
1456  }
1457  $feedback .= '</tbody></table>';
1458 
1459  return $this->object->prepareTextareaOutput($feedback, TRUE);
1460  }
1461 
1472  {
1473  return array();
1474  }
1475 
1486  {
1487  return array();
1488  }
1489 
1498  public function getAggregatedAnswersView($relevant_answers)
1499  {
1500  $overview = array();
1501  $aggregation = array();
1502  foreach ($relevant_answers as $answer)
1503  {
1504  $overview[$answer['active_fi']][$answer['pass']][$answer['value1']] = $answer['value2'];
1505  }
1506 
1507  foreach($overview as $active)
1508  {
1509  foreach ($active as $answer)
1510  {
1511  foreach ($answer as $option => $value)
1512  {
1513  $aggregation[$option][$value] = $aggregation[$option][$value] + 1;
1514  }
1515  }
1516  }
1517 
1518  $html = '<div>';
1519  $i = 0;
1520  foreach ($this->object->getGaps() as $gap)
1521  {
1522  if ($gap->type == CLOZE_SELECT)
1523  {
1524  $html .= '<p>Gap '. ($i+1) . ' - SELECT</p>';
1525  $html .= '<ul>';
1526  $j = 0;
1527  foreach($gap->getItems($this->object->getShuffler()) as $gap_item)
1528  {
1529  $aggregate = $aggregation[$i];
1530  $html .= '<li>' . $gap_item->getAnswerText() . ' - ' . ($aggregate[$j] ? $aggregate[$j] : 0) . '</li>';
1531  $j++;
1532  }
1533  $html .= '</ul>';
1534  }
1535 
1536  if($gap->type == CLOZE_TEXT)
1537  {
1538  $present_elements = array();
1539  foreach($gap->getItems(new ilArrayElementShuffler()) as $item)
1540  {
1542  $present_elements[] = $item->getAnswertext();
1543  }
1544 
1545  $html .= '<p>Gap ' . ($i+1) . ' - TEXT</p>';
1546  $html .= '<ul>';
1547  $aggregate = (array)$aggregation[$i];
1548  foreach($aggregate as $answer => $count)
1549  {
1550  $show_mover = '';
1551  if(in_array($answer, $present_elements))
1552  {
1553  $show_mover = ' style="display: none;" ';
1554  }
1555 
1556  $html .= '<li>' . $answer . ' - ' . $count
1557  . '&nbsp;<button class="clone_fields_add btn btn-link" ' . $show_mover . ' data-answer="'.$answer.'" name="add_gap_'.$i.'_0">
1558  <span class="sr-only"></span><span class="glyphicon glyphicon-plus"></span></button>
1559  </li>';
1560  }
1561  $html .= '</ul>';
1562  }
1563 
1564  if($gap->type == CLOZE_NUMERIC)
1565  {
1566  $html .= '<p>Gap ' . ($i+1) . ' - NUMERIC</p>';
1567  $html .= '<ul>';
1568  $j = 0;
1569  foreach($gap->getItems($this->object->getShuffler()) as $gap_item)
1570  {
1571  $aggregate = (array)$aggregation[$i];
1572  foreach($aggregate as $answer => $count)
1573  {
1574  $html .= '<li>' . $answer . ' - ' . $count . '</li>';
1575  }
1576  $j++;
1577  }
1578  $html .= '</ul>';
1579  }
1580  $i++;
1581  $html .= '<hr />';
1582  }
1583 
1584  $html .= '</div>';
1585  return $html;
1586  }
1587 
1588  public function applyIndizesToGapText( $question_text )
1589  {
1590  $parts = explode( '[gap', $question_text );
1591  $i = 0;
1592  $question_text = '';
1593  foreach ( $parts as $part )
1594  {
1595  if ( $i == 0 )
1596  {
1597  $question_text .= $part;
1598  }
1599  else
1600  {
1601  $question_text .= '[gap ' . $i . $part;
1602  }
1603  $i++;
1604  }
1605  return $question_text;
1606  }
1607 
1608  public function removeIndizesFromGapText( $question_text )
1609  {
1610  $parts = preg_split( '/\[gap \d*\]/', $question_text );
1611  $question_text = implode( '[gap]', $parts );
1612  return $question_text;
1613  }
1614 
1619  private function populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
1620  {
1621  if( $this->isPdfOutputMode() || $this->isContentEditingOutputMode() )
1622  {
1623  $gaptemplate->setCurrentBlock('gap_span');
1624  $gaptemplate->setVariable('SPAN_SOLUTION', $solutiontext);
1625  }
1626  elseif($gap->getType() == CLOZE_SELECT)
1627  {
1628  $gaptemplate->setCurrentBlock('gap_select');
1629  $gaptemplate->setVariable('SELECT_SOLUTION', $solutiontext);
1630  }
1631  else
1632  {
1633  $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->object->getFixedTextLength();
1634 
1635  if($gap_size > 0)
1636  {
1637  $gaptemplate->setCurrentBlock('gap_size');
1638  $gaptemplate->setVariable("GAP_SIZE", $gap_size);
1639  $gaptemplate->parseCurrentBlock();
1640  }
1641 
1642  $gaptemplate->setCurrentBlock('gap_input');
1643  $gaptemplate->setVariable('INPUT_SOLUTION', $solutiontext);
1644  }
1645 
1646 
1647  $gaptemplate->parseCurrentBlock();
1648  }
1649 }
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.
writePostData()
Evaluates a posted edit form and writes the form data in the question object.
getSpecificFeedbackOutput($active_id, $pass)
$_POST['username']
Definition: cron.php:12
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
This class represents a property form user interface.
removeIndizesFromGapText( $question_text)
$_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.
isLastSolutionSubmitAuthorized($active_id, $pass)
fetches solutions from database and prefers intermediate solutions, but falls back to authorized solu...
$cmd
Definition: sahs_server.php:35
getTestOutputSolutions($activeId, $pass)
setValue($a_value)
Set Value.
This class represents a checkbox property in a property form.
addItem($a_item)
Add Item (Property, SectionHeader).
$url
Definition: shib_logout.php:72
populateTextGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a text gap.
setQuestionTabs()
Sets the ILIAS tabs for this question type.
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.
editQuestion($checkonly=FALSE)
Creates an output of the edit form for the question.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
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.
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(!is_array($argv)) $options
$header
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.
getTestOutput( $active_id, $pass, $is_postponed=FALSE, $use_post_solutions=FALSE, $show_feedback=FALSE)
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)
Evaluates a posted edit form and writes the form data in the question object.
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
setMaxLength($a_maxlength)
Set Max Length.
Basic GUI class for assessment questions.
applyIndizesToGapText( $question_text)
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.
removegap()
Remove a gap answer.
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.
__construct($id=-1)
assClozeTestGUI constructor
$errors
& _getUsedHTMLTags($a_module="")
Returns an array of all allowed HTML tags for text editing.
This class represents a text area property in a property form.
addBackTab(ilTabsGUI $ilTabs)
setInlineStyle($a_style)
Set inline style.
Interface ilGuiAnswerScoringAdjustable.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="")
output question page
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.
getPreview($show_question_only=FALSE, $showInlineFeedback=false)
Creates a preview output of the question.
$html
Definition: example_001.php:87
setRequired($a_required)
Set Required.
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
$test
Definition: Utf8Test.php:85
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.