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
4require_once './Modules/TestQuestionPool/classes/class.assQuestionGUI.php';
5require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiQuestionScoringAdjustable.php';
6require_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();
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
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 {
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}
sprintf('%.4f', $callTime)
$test
Definition: Utf8Test.php:84
$_GET["client_id"]
$_POST["username"]
An exception for terminatinating execution or to throw for unit testing.
Class for cloze question numeric answers.
Cloze test question GUI representation.
getAnswerFeedbackOutput($active_id, $pass)
Returns the answer generic feedback depending on the results of the question.
__construct($id=-1)
assClozeTestGUI constructor
editQuestion($checkonly=FALSE)
Creates an output of the edit form for the question.
getTestOutput( $active_id, $pass, $is_postponed=FALSE, $use_post_solutions=FALSE, $show_feedback=FALSE)
populateSelectGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a select gap.
populateNumericGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a numeric gap.
createGaps()
Create gaps from cloze text.
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getPreview($show_question_only=FALSE, $showInlineFeedback=false)
Creates a preview output of the question.
$gapIndex
A temporary variable to store gap indexes of ilCtrl commands in the getCommand method.
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question 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.
getSpecificFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
populateGapSizeFormPart($form, $gap, $gapCounter)
setQuestionTabs()
Sets the ILIAS tabs for this question type.
getBestSolutionText($gap, $gap_index, $gap_combinations)
populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
populateTextGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a text gap.
populateGapFormPart($form, $gapCounter)
Populates a gap form-part.
addgap()
Add a gap answer.
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
removeIndizesFromGapText( $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.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
Adds the answer specific form parts to a question property form gui.
writePostData($always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question,...
removegap()
Remove a gap answer.
applyIndizesToGapText( $question_text)
Class for cloze tests.
Basic GUI class for assessment questions.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.
getILIASPage($html="")
Returns the ILIAS Page around a question.
getQuestionTemplate()
get question template
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="")
output question page
addBackTab(ilTabsGUI $ilTabs)
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
const ADDITIONAL_CONTENT_EDITING_MODE_DEFAULT
constant for additional content editing mode "default"
This class represents a single choice wizard property in a property form.
static getSelfAssessmentTags()
Get tags allowed in question tags in self assessment mode.
This class represents a checkbox property in a property form.
This class represents a custom property in a property form.
This class represents a duration (typical hh:mm:ss) property in a property form.
This class represents a section header in a property form.
This class represents a formula text property in a property form.
This class represents a hidden form property in a property form.
This class represents a number property in a property form.
static _getUsedHTMLTags($a_module="")
Returns an array of all allowed HTML tags for text editing.
static getManualFeedback($active_id, $question_id, $pass)
Retrieves the manual feedback for a question in a test.
This class represents a property form user interface.
addItem($a_item)
Add Item (Property, SectionHeader).
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
This class represents a text area property in a property form.
This class represents a text property in a property form.
static stripSlashesRecursive($a_data, $a_strip_html=true, $a_allow="")
Strip slashes from array and sub-arrays.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
$html
Definition: example_001.php:87
$header
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\s+" &#(? foreach( $entity_files as $file) $output
const CLOZE_NUMERIC
const CLOZE_SELECT
const CLOZE_TEXT
Cloze question constants.
Interface ilGuiAnswerScoringAdjustable.
Interface ilGuiQuestionScoringAdjustable.
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
$cmd
Definition: sahs_server.php:35
$url
Definition: shib_logout.php:72
$errors
if(!is_array($argv)) $options