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