ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assClozeTestGUI.php
Go to the documentation of this file.
1 <?php
2  /*
3  +----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +----------------------------------------------------------------------------+
22 */
23 
24 include_once "./Modules/TestQuestionPool/classes/class.assQuestionGUI.php";
25 
38 {
42  private $gapIndex;
43 
49  function __construct($id = -1)
50  {
52  include_once "./Modules/TestQuestionPool/classes/class.assClozeTest.php";
53  $this->object = new assClozeTest();
54  if ($id >= 0)
55  {
56  $this->object->loadFromDb($id);
57  }
58  }
59 
60  function getCommand($cmd)
61  {
62  if (preg_match("/^(removegap|addgap)_(\d+)$/", $cmd, $matches))
63  {
64  $cmd = $matches[1];
65  $this->gapIndex = $matches[2];
66  }
67  return $cmd;
68  }
69 
76  function writePostData($always = false)
77  {
78  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
79  if (!$hasErrors)
80  {
81  $this->object->flushGaps();
82  $this->object->setTitle($_POST["title"]);
83  $this->object->setAuthor($_POST["author"]);
84  $this->object->setComment($_POST["comment"]);
85  $this->object->setTextgapRating($_POST["textgap_rating"]);
86  $this->object->setIdenticalScoring($_POST["identical_scoring"]);
87  if ($this->getSelfAssessmentEditingMode())
88  {
89  $this->object->setNrOfTries($_POST['nr_of_tries']);
90  }
91  $this->object->setFixedTextLength($_POST["fixedTextLength"]);
92  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
93  $cloze_text = $_POST["question"];
94  $this->object->setClozeText($cloze_text);
95  $this->object->setEstimatedWorkingTime(
96  $_POST["Estimated"]["hh"],
97  $_POST["Estimated"]["mm"],
98  $_POST["Estimated"]["ss"]
99  );
100 
101  if (is_array($_POST['gap']))
102  {
103  if (strcmp($this->ctrl->getCmd(), 'createGaps') != 0) $this->object->clearGapAnswers();
104  foreach ($_POST['gap'] as $idx => $hidden)
105  {
106  $clozetype = $_POST['clozetype_' . $idx];
107  $this->object->setGapType($idx, $clozetype);
108  if (array_key_exists('shuffle_' . $idx, $_POST))
109  {
110  $this->object->setGapShuffle($idx, $_POST['shuffle_' . $idx]);
111  }
112 
113  if (strcmp($this->ctrl->getCmd(), 'createGaps') != 0)
114  {
115  if (is_array($_POST['gap_' . $idx]['answer']))
116  {
117  foreach ($_POST['gap_' . $idx]['answer'] as $order => $value)
118  {
119  $this->object->addGapAnswer($idx, $order, $value);
120  }
121  }
122  }
123  if (array_key_exists('gap_' . $idx . '_numeric', $_POST))
124  {
125  if (strcmp($this->ctrl->getCmd(), 'createGaps') != 0) $this->object->addGapAnswer($idx, 0, str_replace(",", ".", $_POST['gap_' . $idx . '_numeric']));
126  $this->object->setGapAnswerLowerBound($idx, 0, str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_lower']));
127  $this->object->setGapAnswerUpperBound($idx, 0, str_replace(",", ".", $_POST['gap_' . $idx . '_numeric_upper']));
128  $this->object->setGapAnswerPoints($idx, 0, $_POST['gap_' . $idx . '_numeric_points']);
129  }
130  if (is_array($_POST['gap_' . $idx]['points']))
131  {
132  foreach ($_POST['gap_' . $idx]['points'] as $order => $value)
133  {
134  $this->object->setGapAnswerPoints($idx, $order, $value);
135  }
136  }
137  }
138  if (strcmp($this->ctrl->getCmd(), 'createGaps') != 0) $this->object->updateClozeTextFromGaps();
139  }
140  return 0;
141  }
142  else
143  {
144  return 1;
145  }
146  }
147 
153  public function editQuestion($checkonly = FALSE)
154  {
155  $save = $this->isSaveCommand();
156  $this->getQuestionTemplate();
157 
158 # if ($_REQUEST['prev_qid']) {
159 # $this->ctrl->setParameter($this, 'prev_qid', $_REQUEST['prev_qid']);
160 # }
161 
162  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
163  $form = new ilPropertyFormGUI();
164  $form->setFormAction($this->ctrl->getFormAction($this));
165  $form->setTitle($this->outQuestionType());
166  $form->setMultipart(FALSE);
167  $form->setTableWidth("100%");
168  $form->setId("assclozetest");
169 
170  // title, author, description, question, working time (assessment mode)
171  $this->addBasicQuestionFormProperties($form);
172  $q_item = $form->getItemByPostVar("question");
173  $q_item->setInfo($this->lng->txt("close_text_hint"));
174  $q_item->setTitle($this->lng->txt("cloze_text"));
175 
176  // text rating
177  if (!$this->getSelfAssessmentEditingMode())
178  {
179  $textrating = new ilSelectInputGUI($this->lng->txt("text_rating"), "textgap_rating");
180  $text_options = array(
181  "ci" => $this->lng->txt("cloze_textgap_case_insensitive"),
182  "cs" => $this->lng->txt("cloze_textgap_case_sensitive"),
183  "l1" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "1"),
184  "l2" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "2"),
185  "l3" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "3"),
186  "l4" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "4"),
187  "l5" => sprintf($this->lng->txt("cloze_textgap_levenshtein_of"), "5")
188  );
189  $textrating->setOptions($text_options);
190  $textrating->setValue($this->object->getTextgapRating());
191  $form->addItem($textrating);
192 
193  // text field length
194  $fixedTextLength = new ilNumberInputGUI($this->lng->txt("cloze_fixed_textlength"), "fixedTextLength");
195  $fixedTextLength->setValue(ilUtil::prepareFormOutput($this->object->getFixedTextLength()));
196  $fixedTextLength->setMinValue(0);
197  $fixedTextLength->setSize(3);
198  $fixedTextLength->setMaxLength(6);
199  $fixedTextLength->setInfo($this->lng->txt('cloze_fixed_textlength_description'));
200  $fixedTextLength->setRequired(false);
201  $form->addItem($fixedTextLength);
202 
203  // identical scoring
204  $identical_scoring = new ilCheckboxInputGUI($this->lng->txt("identical_scoring"), "identical_scoring");
205  $identical_scoring->setValue(1);
206  $identical_scoring->setChecked($this->object->getIdenticalScoring());
207  $identical_scoring->setInfo($this->lng->txt('identical_scoring_desc'));
208  $identical_scoring->setRequired(FALSE);
209  $form->addItem($identical_scoring);
210  }
211 
212  for ($i = 0; $i < $this->object->getGapCount(); $i++)
213  {
214  $gap = $this->object->getGap($i);
215  $header = new ilFormSectionHeaderGUI();
216  $header->setTitle($this->lng->txt("gap") . " " . ($i+1));
217  $form->addItem($header);
218 
219  $gapcounter = new ilHiddenInputGUI("gap[$i]");
220  $gapcounter->setValue($i);
221  $form->addItem($gapcounter);
222 
223  $gaptype = new ilSelectInputGUI($this->lng->txt('type'), "clozetype_$i");
224  $options = array(
225  0 => $this->lng->txt("text_gap"),
226  1 => $this->lng->txt("select_gap"),
227  2 => $this->lng->txt("numeric_gap")
228  );
229  $gaptype->setOptions($options);
230  $gaptype->setValue($gap->getType());
231  $form->addItem($gaptype);
232 
233  if ($gap->getType() == CLOZE_TEXT)
234  {
235  // Choices
236  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
237  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
238  $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $i . "");
239  $values->setRequired(true);
240  $values->setQuestionObject($this->object);
241  $values->setSingleline(true);
242  $values->setAllowMove(false);
243  if (count($gap->getItemsRaw()) == 0) $gap->addItem(new assAnswerCloze("", 0, 0));
244  $values->setValues($gap->getItemsRaw());
245  $form->addItem($values);
246 
247  if( $this->object->getFixedTextLength() > 0 )
248  {
249  $values->setSize($this->object->getFixedTextLength());
250  $values->setMaxLength($this->object->getFixedTextLength());
251  }
252  }
253  else if ($gap->getType() == CLOZE_SELECT)
254  {
255  include_once "./Modules/TestQuestionPool/classes/class.ilAnswerWizardInputGUI.php";
256  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
257  $values = new ilAnswerWizardInputGUI($this->lng->txt("values"), "gap_" . $i . "");
258  $values->setRequired(true);
259  $values->setQuestionObject($this->object);
260  $values->setSingleline(true);
261  $values->setAllowMove(false);
262  if (count($gap->getItemsRaw()) == 0) $gap->addItem(new assAnswerCloze("", 0, 0));
263  $values->setValues($gap->getItemsRaw());
264  $form->addItem($values);
265 
266  // shuffle
267  $shuffle = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_" . $i . "");
268  $shuffle->setValue(1);
269  $shuffle->setChecked($gap->getShuffle());
270  $shuffle->setRequired(FALSE);
271  $form->addItem($shuffle);
272  }
273  else if ($gap->getType() == CLOZE_NUMERIC)
274  {
275  if (count($gap->getItemsRaw()) == 0) $gap->addItem(new assAnswerCloze("", 0, 0));
276  foreach ($gap->getItemsRaw() as $item)
277  {
278  // #8944: the js-based ouput in self-assessment cannot support formulas
279  if(!$this->getSelfAssessmentEditingMode())
280  {
281  $value = new ilFormulaInputGUI($this->lng->txt('value'), "gap_" . $i . "_numeric");
282  $value->setInlineStyle('text-align: right;');
283 
284  $lowerbound = new ilFormulaInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $i . "_numeric_lower");
285  $lowerbound->setInlineStyle('text-align: right;');
286 
287  $upperbound = new ilFormulaInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $i . "_numeric_upper");
288  $upperbound->setInlineStyle('text-align: right;');
289  }
290  else
291  {
292  $value = new ilNumberInputGUI($this->lng->txt('value'), "gap_" . $i . "_numeric");
293  $value->allowDecimals(true);
294 
295  $lowerbound = new ilNumberInputGUI($this->lng->txt('range_lower_limit'), "gap_" . $i . "_numeric_lower");
296  $lowerbound->allowDecimals(true);
297 
298  $upperbound = new ilNumberInputGUI($this->lng->txt('range_upper_limit'), "gap_" . $i . "_numeric_upper");
299  $upperbound->allowDecimals(true);
300  }
301 
302  $value->setSize(10);
303  $value->setValue(ilUtil::prepareFormOutput($item->getAnswertext()));
304  $value->setRequired(true);
305  $form->addItem($value);
306 
307  $lowerbound->setSize(10);
308  $lowerbound->setRequired(true);
309  $lowerbound->setValue(ilUtil::prepareFormOutput($item->getLowerBound()));
310  $form->addItem($lowerbound);
311 
312  $upperbound->setSize(10);
313  $upperbound->setRequired(true);
314  $upperbound->setValue(ilUtil::prepareFormOutput($item->getUpperBound()));
315  $form->addItem($upperbound);
316 
317  if( $this->object->getFixedTextLength() > 0 )
318  {
319  $value->setSize($this->object->getFixedTextLength());
320  $value->setMaxLength($this->object->getFixedTextLength());
321  $lowerbound->setSize($this->object->getFixedTextLength());
322  $lowerbound->setMaxLength($this->object->getFixedTextLength());
323  $upperbound->setSize($this->object->getFixedTextLength());
324  $upperbound->setMaxLength($this->object->getFixedTextLength());
325  }
326 
327  $points = new ilNumberInputGUI($this->lng->txt('points'), "gap_" . $i . "_numeric_points");
328  $points->allowDecimals(true);
329  $points->setSize(3);
330  $points->setRequired(true);
331  $points->setValue(ilUtil::prepareFormOutput($item->getPoints()));
332  $form->addItem($points);
333  }
334  }
335  }
336 
337  $form->addCommandButton('createGaps', $this->lng->txt('create_gaps'));
338  $this->addQuestionFormCommandButtons($form);
339 
340  $errors = false;
341 
342  if ($save)
343  {
344  $form->setValuesByPost();
345  $errors = !$form->checkInput();
346  $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we need this if we don't want to have duplication of backslashes
347  if ($errors) $checkonly = false;
348  }
349 
350  if (!$checkonly) $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
351  return $errors;
352  }
353 
357  public function createGaps()
358  {
359  $this->writePostData(true);
360  $this->object->saveToDb();
361  $this->editQuestion();
362  }
363 
367  function removegap()
368  {
369  $this->writePostData(true);
370  $this->object->deleteAnswerText($this->gapIndex, key($_POST['cmd']['removegap_' . $this->gapIndex]));
371  $this->editQuestion();
372  }
373 
377  function addgap()
378  {
379  $this->writePostData(true);
380  $this->object->addGapAnswer($this->gapIndex, key($_POST['cmd']['addgap_' . $this->gapIndex])+1, "");
381  $this->editQuestion();
382  }
383 
396  function outQuestionForTest($formaction, $active_id, $pass = NULL, $is_postponed = FALSE, $use_post_solutions = FALSE)
397  {
398  $test_output = $this->getTestOutput($active_id, $pass, $is_postponed, $use_post_solutions);
399  $this->tpl->setVariable("QUESTION_OUTPUT", $test_output);
400  $this->tpl->setVariable("FORMACTION", $formaction);
401  }
402 
411  function getPreview($show_question_only = FALSE)
412  {
413  // generate the question output
414  include_once "./Services/UICore/classes/class.ilTemplate.php";
415  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
416  $output = $this->object->getClozeText();
417  foreach ($this->object->getGaps() as $gap_index => $gap)
418  {
419  switch ($gap->getType())
420  {
421  case CLOZE_TEXT:
422  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", TRUE, TRUE, "Modules/TestQuestionPool");
423  $gaptemplate->setVariable("TEXT_GAP_SIZE", $this->object->getFixedTextLength() ? $this->object->getFixedTextLength() : $gap->getMaxWidth());
424  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
425  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
426  break;
427  case CLOZE_SELECT:
428  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", TRUE, TRUE, "Modules/TestQuestionPool");
429  foreach ($gap->getItems() as $item)
430  {
431  $gaptemplate->setCurrentBlock("select_gap_option");
432  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
433  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
434  $gaptemplate->parseCurrentBlock();
435  }
436  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
437  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
438  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
439  break;
440  case CLOZE_NUMERIC:
441  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", TRUE, TRUE, "Modules/TestQuestionPool");
442  $gaptemplate->setVariable("TEXT_GAP_SIZE", $this->object->getFixedTextLength() ? $this->object->getFixedTextLength() : $gap->getMaxWidth());
443  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
444  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
445  break;
446  }
447  }
448  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($output, TRUE));
449  $questionoutput = $template->get();
450  if (!$show_question_only)
451  {
452  // get page object output
453  $questionoutput = $this->getILIASPage($questionoutput);
454  }
455  return $questionoutput;
456  }
457 
472  $active_id,
473  $pass = NULL,
474  $graphicalOutput = FALSE,
475  $result_output = FALSE,
476  $show_question_only = TRUE,
477  $show_feedback = FALSE,
478  $show_correct_solution = FALSE,
479  $show_manual_scoring = FALSE,
480  $show_question_text = TRUE
481  )
482  {
483  // get the solution of the user for the active pass or from the last pass if allowed
484  $user_solution = array();
485  if (($active_id > 0) && (!$show_correct_solution))
486  {
487  // get the solutions of a user
488  $user_solution =& $this->object->getSolutionValues($active_id, $pass);
489  if (!is_array($user_solution))
490  {
491  $user_solution = array();
492  }
493  } else {
494  foreach ($this->object->gaps as $index => $gap)
495  {
496  $user_solution = array();
497 
498  }
499  }
500 
501  include_once "./Services/UICore/classes/class.ilTemplate.php";
502  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution.html", TRUE, TRUE, "Modules/TestQuestionPool");
503  $output = $this->object->getClozeText();
504  foreach ($this->object->getGaps() as $gap_index => $gap)
505  {
506  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_output_solution_gap.html", TRUE, TRUE, "Modules/TestQuestionPool");
507  $found = array();
508  foreach ($user_solution as $solutionarray)
509  {
510  if ($solutionarray["value1"] == $gap_index) $found = $solutionarray;
511  }
512 
513  if ($active_id)
514  {
515  if ($graphicalOutput)
516  {
517  // output of ok/not ok icons for user entered solutions
518  $details = $this->object->calculateReachedPoints($active_id, $pass, TRUE);
519  $check = $details[$gap_index];
520  if ($check["best"])
521  {
522  $gaptemplate->setCurrentBlock("icon_ok");
523  $gaptemplate->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.png"));
524  $gaptemplate->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
525  $gaptemplate->parseCurrentBlock();
526  }
527  else
528  {
529  $gaptemplate->setCurrentBlock("icon_not_ok");
530  if ($check["positive"])
531  {
532  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_mostly_ok.png"));
533  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_not_correct_but_positive"));
534  }
535  else
536  {
537  $gaptemplate->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.png"));
538  $gaptemplate->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
539  }
540  $gaptemplate->parseCurrentBlock();
541  }
542  }
543  }
544  if ($result_output)
545  {
546  $points = $this->object->getMaximumGapPoints($gap_index);
547  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
548  $gaptemplate->setCurrentBlock("result_output");
549  $gaptemplate->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
550  $gaptemplate->parseCurrentBlock();
551  }
552  switch ($gap->getType())
553  {
554  case CLOZE_TEXT:
555  $solutiontext = "";
556  if (($active_id > 0) && (!$show_correct_solution))
557  {
558  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
559  {
560  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
561  {
562  $solutiontext .= "&nbsp;";
563  }
564  }
565  else
566  {
567  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
568  }
569  }
570  else
571  {
572  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput());
573  }
574  $gaptemplate->setVariable("SOLUTION", $solutiontext);
575  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
576  break;
577  case CLOZE_SELECT:
578  $solutiontext = "";
579  if (($active_id > 0) && (!$show_correct_solution))
580  {
581  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
582  {
583  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
584  {
585  $solutiontext .= "&nbsp;";
586  }
587  }
588  else
589  {
590  $item = $gap->getItem($found["value2"]);
591  if (is_object($item))
592  {
593  $solutiontext = ilUtil::prepareFormOutput($item->getAnswertext());
594  }
595  else
596  {
597  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
598  {
599  $solutiontext .= "&nbsp;";
600  }
601  }
602  }
603  }
604  else
605  {
606  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput());
607  }
608  $gaptemplate->setVariable("SOLUTION", $solutiontext);
609  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
610  break;
611  case CLOZE_NUMERIC:
612  $solutiontext = "";
613  if (($active_id > 0) && (!$show_correct_solution))
614  {
615  if ((count($found) == 0) || (strlen(trim($found["value2"])) == 0))
616  {
617  for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++)
618  {
619  $solutiontext .= "&nbsp;";
620  }
621  }
622  else
623  {
624  $solutiontext = ilUtil::prepareFormOutput($found["value2"]);
625  }
626  }
627  else
628  {
629  $solutiontext = ilUtil::prepareFormOutput($gap->getBestSolutionOutput());
630  }
631  $gaptemplate->setVariable("SOLUTION", $solutiontext);
632  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
633  break;
634  }
635  }
636 
637  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($output, TRUE));
638  // generate the question output
639  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html",TRUE, TRUE, "Modules/TestQuestionPool");
640  $questionoutput = $template->get();
641 
642  $feedback = '';
643  if($show_feedback)
644  {
645  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
646  $feedback .= strlen($fb) ? $fb : '';
647 
648  $fb = $this->getSpecificFeedbackOutput($active_id, $pass);
649  $feedback .= strlen($fb) ? $fb : '';
650  }
651  if (strlen($feedback)) $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
652 
653  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
654 
655  $solutionoutput = $solutiontemplate->get();
656 
657  if (!$show_question_only)
658  {
659  // get page object output
660  $solutionoutput = '<div class="ilc_question_Standard">'.$solutionoutput."</div>";
661  }
662 
663  return $solutionoutput;
664  }
665 
666  public function getAnswerFeedbackOutput($active_id, $pass)
667  {
668  include_once "./Modules/Test/classes/class.ilObjTest.php";
669  $manual_feedback = ilObjTest::getManualFeedback($active_id, $this->object->getId(), $pass);
670  if (strlen($manual_feedback))
671  {
672  return $manual_feedback;
673  }
674  $correct_feedback = $this->object->getFeedbackGeneric(1);
675  $incorrect_feedback = $this->object->getFeedbackGeneric(0);
676  if (strlen($correct_feedback.$incorrect_feedback))
677  {
678  $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
679  $max_points = $this->object->getMaximumPoints();
680  if ($reached_points == $max_points)
681  {
682  $output .= $correct_feedback;
683  }
684  else
685  {
686  $output .= $incorrect_feedback;
687  }
688  }
689  $test = new ilObjTest($this->object->active_id);
690  return $this->object->prepareTextareaOutput($output, TRUE);
691  }
692 
693  function getTestOutput($active_id, $pass = NULL, $is_postponed = FALSE, $use_post_solutions = FALSE, $show_feedback = FALSE)
694  {
695  // get the solution of the user for the active pass or from the last pass if allowed
696  $user_solution = array();
697  if ($active_id)
698  {
699  include_once "./Modules/Test/classes/class.ilObjTest.php";
700  if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
701  {
702  if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
703  }
704  $user_solution =& $this->object->getSolutionValues($active_id, $pass);
705  if (!is_array($user_solution))
706  {
707  $user_solution = array();
708  }
709  }
710 
711  // generate the question output
712  include_once "./Services/UICore/classes/class.ilTemplate.php";
713  $template = new ilTemplate("tpl.il_as_qpl_cloze_question_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
714  $output = $this->object->getClozeText();
715  foreach ($this->object->getGaps() as $gap_index => $gap)
716  {
717  switch ($gap->getType())
718  {
719  case CLOZE_TEXT:
720  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_text.html", TRUE, TRUE, "Modules/TestQuestionPool");
721  $gaptemplate->setVariable("TEXT_GAP_SIZE", $this->object->getFixedTextLength() ? $this->object->getFixedTextLength() : $gap->getMaxWidth());
722  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
723  foreach ($user_solution as $solution)
724  {
725  if (strcmp($solution["value1"], $gap_index) == 0)
726  {
727  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
728  }
729  }
730  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
731  break;
732  case CLOZE_SELECT:
733  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_select.html", TRUE, TRUE, "Modules/TestQuestionPool");
734  foreach ($gap->getItems() as $item)
735  {
736  $gaptemplate->setCurrentBlock("select_gap_option");
737  $gaptemplate->setVariable("SELECT_GAP_VALUE", $item->getOrder());
738  $gaptemplate->setVariable("SELECT_GAP_TEXT", ilUtil::prepareFormOutput($item->getAnswerText()));
739  foreach ($user_solution as $solution)
740  {
741  if (strcmp($solution["value1"], $gap_index) == 0)
742  {
743  if (strcmp($solution["value2"], $item->getOrder()) == 0)
744  {
745  $gaptemplate->setVariable("SELECT_GAP_SELECTED", " selected=\"selected\"");
746  }
747  }
748  }
749  $gaptemplate->parseCurrentBlock();
750  }
751  $gaptemplate->setVariable("PLEASE_SELECT", $this->lng->txt("please_select"));
752  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
753  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
754  break;
755  case CLOZE_NUMERIC:
756  $gaptemplate = new ilTemplate("tpl.il_as_qpl_cloze_question_gap_numeric.html", TRUE, TRUE, "Modules/TestQuestionPool");
757  $gaptemplate->setVariable("TEXT_GAP_SIZE", $this->object->getFixedTextLength() ? $this->object->getFixedTextLength() : $gap->getMaxWidth());
758  $gaptemplate->setVariable("GAP_COUNTER", $gap_index);
759  foreach ($user_solution as $solution)
760  {
761  if (strcmp($solution["value1"], $gap_index) == 0)
762  {
763  $gaptemplate->setVariable("VALUE_GAP", " value=\"" . ilUtil::prepareFormOutput($solution["value2"]) . "\"");
764  }
765  }
766  $output = preg_replace("/\[gap\].*?\[\/gap\]/", $gaptemplate->get(), $output, 1);
767  break;
768  }
769  }
770 
771  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($output, TRUE));
772  $questionoutput = $template->get();
773  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
774  return $pageoutput;
775  }
776 
782  function saveFeedback()
783  {
784  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
785  $errors = $this->feedback(true);
786  $this->object->saveFeedbackGeneric(0, $_POST["feedback_incomplete"]);
787  $this->object->saveFeedbackGeneric(1, $_POST["feedback_complete"]);
788  foreach ($this->object->gaps as $index => $answer)
789  {
790  $this->object->saveFeedbackSingleAnswer($index, $_POST["feedback_answer_$index"]);
791  }
792  $this->object->cleanupMediaObjectUsage();
794  }
795 
803  function setQuestionTabs()
804  {
805  global $rbacsystem, $ilTabs;
806 
807  $this->ctrl->setParameterByClass("ilpageobjectgui", "q_id", $_GET["q_id"]);
808  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
809  $q_type = $this->object->getQuestionType();
810 
811  if (strlen($q_type))
812  {
813  $classname = $q_type . "GUI";
814  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
815  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
816 # $this->ctrl->setParameterByClass(strtolower($classname), 'prev_qid', $_REQUEST['prev_qid']);
817  }
818 
819  if ($_GET["q_id"])
820  {
821  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
822  {
823  // edit page
824  $ilTabs->addTarget("edit_page",
825  $this->ctrl->getLinkTargetByClass("ilPageObjectGUI", "edit"),
826  array("edit", "insert", "exec_pg"),
827  "", "", $force_active);
828  }
829 
830  // edit page
831  $ilTabs->addTarget("preview",
832  $this->ctrl->getLinkTargetByClass("ilPageObjectGUI", "preview"),
833  array("preview"),
834  "ilPageObjectGUI", "", $force_active);
835  }
836 
837  $force_active = false;
838  $commands = $_POST["cmd"];
839  if (is_array($commands))
840  {
841  foreach ($commands as $key => $value)
842  {
843  if (preg_match("/^removegap_.*/", $key, $matches) ||
844  preg_match("/^addgap_.*/", $key, $matches)
845  )
846  {
847  $force_active = true;
848  }
849  }
850  }
851  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
852  {
853  $url = "";
854  if ($classname) $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
855  // edit question properties
856  $ilTabs->addTarget("edit_question",
857  $url,
858  array("editQuestion", "originalSyncForm", "save", "createGaps", "saveEdit"),
859  $classname, "", $force_active);
860  }
861 
862  if ($_GET["q_id"])
863  {
864  $ilTabs->addTarget("feedback",
865  $this->ctrl->getLinkTargetByClass($classname, "feedback"),
866  array("feedback", "saveFeedback"),
867  $classname, "");
868  }
869 
870  // add tab for question hint within common class assQuestionGUI
871  $this->addTab_QuestionHints($ilTabs);
872 
873  if ($_GET["q_id"])
874  {
875  $ilTabs->addTarget("solution_hint",
876  $this->ctrl->getLinkTargetByClass($classname, "suggestedsolution"),
877  array("suggestedsolution", "saveSuggestedSolution", "outSolutionExplorer", "cancel",
878  "addSuggestedSolution","cancelExplorer", "linkChilds", "removeSuggestedSolution"
879  ),
880  $classname,
881  ""
882  );
883  }
884 
885  // Assessment of questions sub menu entry
886  if ($_GET["q_id"])
887  {
888  $ilTabs->addTarget("statistics",
889  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
890  array("assessment"),
891  $classname, "");
892  }
893 
894  if (($_GET["calling_test"] > 0) || ($_GET["test_ref_id"] > 0))
895  {
896  $ref_id = $_GET["calling_test"];
897  if (strlen($ref_id) == 0) $ref_id = $_GET["test_ref_id"];
898 
899  global $___test_express_mode;
900 
901  if (!$_GET['test_express_mode'] && !$___test_express_mode) {
902  $ilTabs->setBackTarget($this->lng->txt("backtocallingtest"), "ilias.php?baseClass=ilObjTestGUI&cmd=questions&ref_id=$ref_id");
903  }
904  else {
906  $ilTabs->setBackTarget($this->lng->txt("backtocallingtest"), $link);
907  }
908  }
909  else
910  {
911  $ilTabs->setBackTarget($this->lng->txt("qpl"), $this->ctrl->getLinkTargetByClass("ilobjquestionpoolgui", "questions"));
912  }
913  }
914 
920  function feedback($checkonly = false)
921  {
922  $save = (strcmp($this->ctrl->getCmd(), "saveFeedback") == 0) ? TRUE : FALSE;
923  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
924  $form = new ilPropertyFormGUI();
925  $form->setFormAction($this->ctrl->getFormAction($this));
926  $form->setTitle($this->lng->txt('feedback_answers'));
927  $form->setTableWidth("100%");
928  $form->setId("feedback");
929 
930  $complete = new ilTextAreaInputGUI($this->lng->txt("feedback_complete_solution"), "feedback_complete");
931  $complete->setValue($this->object->prepareTextareaOutput($this->object->getFeedbackGeneric(1)));
932  $complete->setRequired(false);
933  $complete->setRows(10);
934  $complete->setCols(80);
935  if (!$this->getPreventRteUsage())
936  {
937  $complete->setUseRte(true);
938  }
939  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
940  $complete->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
941  $complete->addPlugin("latex");
942  $complete->addButton("latex");
943  $complete->addButton("pastelatex");
944  $complete->setRTESupport($this->object->getId(), "qpl", "assessment", null, false, '3.4.7');
945  $form->addItem($complete);
946 
947  $incomplete = new ilTextAreaInputGUI($this->lng->txt("feedback_incomplete_solution"), "feedback_incomplete");
948  $incomplete->setValue($this->object->prepareTextareaOutput($this->object->getFeedbackGeneric(0)));
949  $incomplete->setRequired(false);
950  $incomplete->setRows(10);
951  $incomplete->setCols(80);
952  if (!$this->getPreventRteUsage())
953  {
954  $incomplete->setUseRte(true);
955  }
956  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
957  $incomplete->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
958  $incomplete->addPlugin("latex");
959  $incomplete->addButton("latex");
960  $incomplete->addButton("pastelatex");
961  $incomplete->setRTESupport($this->object->getId(), "qpl", "assessment", null, false, '3.4.7');
962  $form->addItem($incomplete);
963 
964  if (!$this->getSelfAssessmentEditingMode())
965  {
966  foreach ($this->object->gaps as $index => $answer)
967  {
968  $caption = 'Gap '.$ordinal = $index+1 .':<i> ';
969  foreach ($answer->items as $item)
970  {
971  $caption .= '"' . $item->answertext.'" / ';
972  }
973  $caption = substr($caption, 0, strlen($caption)-3);
974  $caption .= '</i>';
975 
976  $answerobj = new ilTextAreaInputGUI($this->object->prepareTextareaOutput($caption, true), "feedback_answer_$index");
977  $answerobj->setValue($this->object->prepareTextareaOutput($this->object->getFeedbackSingleAnswer($index)));
978  $answerobj->setRequired(false);
979  $answerobj->setRows(10);
980  $answerobj->setCols(80);
981  $answerobj->setUseRte(true);
982  include_once "./Services/AdvancedEditing/classes/class.ilObjAdvancedEditing.php";
983  $answerobj->setRteTags(ilObjAdvancedEditing::_getUsedHTMLTags("assessment"));
984  $answerobj->addPlugin("latex");
985  $answerobj->addButton("latex");
986  $answerobj->addButton("pastelatex");
987  $answerobj->setRTESupport($this->object->getId(), "qpl", "assessment", null, false, '3.4.7');
988  $form->addItem($answerobj);
989  }
990  }
991 
992  global $ilAccess;
993  if ($ilAccess->checkAccess("write", "", $_GET['ref_id']) || $this->getSelfAssessmentEditingMode())
994  {
995  $form->addCommandButton("saveFeedback", $this->lng->txt("save"));
996  }
997  if ($save)
998  {
999  $form->setValuesByPost();
1000  $errors = !$form->checkInput();
1001  $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we need this if we don't want to have duplication of backslashes
1002  }
1003  if (!$checkonly) $this->tpl->setVariable("ADM_CONTENT", $form->getHTML());
1004  return $errors;
1005  }
1006 
1007  function getSpecificFeedbackOutput($active_id, $pass)
1008  {
1009  $feedback = '<table><tbody>';
1010 
1011  foreach ($this->object->gaps as $index => $answer)
1012  {
1013  $caption = $ordinal = $index+1 .':<i> ';
1014  foreach ($answer->items as $item)
1015  {
1016  $caption .= '"' . $item->answertext.'" / ';
1017  }
1018  $caption = substr($caption, 0, strlen($caption)-3);
1019  $caption .= '</i>';
1020 
1021  $feedback .= '<tr><td>';
1022 
1023  $feedback .= $caption .'</td><td>';
1024  $feedback .= $this->object->getFeedbackSingleAnswer($index) . '</td> </tr>';
1025  }
1026  $feedback .= '</tbody></table>';
1027 
1028  return $this->object->prepareTextareaOutput($feedback, TRUE);
1029  }
1030 }
1031 ?>