ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.assMatchingQuestionGUI.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 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
8 
24 {
35  public function __construct($id = -1)
36  {
37  parent::__construct();
38  include_once "./Modules/TestQuestionPool/classes/class.assMatchingQuestion.php";
39  $this->object = new assMatchingQuestion();
40  $this->setErrorMessage($this->lng->txt("msg_form_save_error"));
41  if ($id >= 0)
42  {
43  $this->object->loadFromDb($id);
44  }
45  }
46 
50  protected function writePostData($always = false)
51  {
52  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
53  if (!$hasErrors)
54  {
55  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
59  $this->saveTaxonomyAssignments();
60  return 0;
61  }
62  return 1;
63  }
64 
66  {
67  // Delete all existing answers and create new answers from the form data
68  $this->object->flushMatchingPairs();
69  $this->object->flushTerms();
70  $this->object->flushDefinitions();
71 
72  // add terms
73  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php';
74  foreach ($_POST['terms']['answer'] as $index => $answer)
75  {
76  $filename = $_POST['terms']['imagename'][$index];
77  if (strlen( $_FILES['terms']['name']['image'][$index] ))
78  {
79  // upload the new file
80  $name = $_FILES['terms']['name']['image'][$index];
81  if ($this->object->setImageFile( $_FILES['terms']['tmp_name']['image'][$index],
82  $this->object->getEncryptedFilename( $name )
83  )
84  )
85  {
86  $filename = $this->object->getEncryptedFilename( $name );
87  }
88  else
89  {
90  $filename = "";
91  }
92  }
93  $this->object->addTerm( new assAnswerMatchingTerm($answer, $filename, $_POST['terms']['identifier'][$index])
94  );
95  }
96  // add definitions
97  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php';
98  foreach ($_POST['definitions']['answer'] as $index => $answer)
99  {
100  $filename = $_POST['definitions']['imagename'][$index];
101  if (strlen( $_FILES['definitions']['name']['image'][$index] ))
102  {
103  // upload the new file
104  $name = $_FILES['definitions']['name']['image'][$index];
105  if ($this->object->setImageFile( $_FILES['definitions']['tmp_name']['image'][$index],
106  $this->object->getEncryptedFilename( $name )
107  )
108  )
109  {
110  $filename = $this->object->getEncryptedFilename( $name );
111  }
112  else
113  {
114  $filename = "";
115  }
116  }
117  $this->object->addDefinition(
118  new assAnswerMatchingDefinition($answer, $filename, $_POST['definitions']['identifier'][$index])
119  );
120  }
121 
122  // add matching pairs
123  if (is_array( $_POST['pairs']['points'] ))
124  {
125  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php';
126  foreach ($_POST['pairs']['points'] as $index => $points)
127  {
128  $term_id = $_POST['pairs']['term'][$index];
129  $definition_id = $_POST['pairs']['definition'][$index];
130  $this->object->addMatchingPair( $this->object->getTermWithIdentifier( $term_id ),
131  $this->object->getDefinitionWithIdentifier( $definition_id ),
132  $points
133  );
134  }
135  }
136  }
137 
139  {
140  if (!$this->object->getSelfAssessmentEditingMode())
141  {
142  $this->object->setShuffle( $_POST["shuffle"] );
143  }
144  else
145  {
146  $this->object->setShuffle( 1 );
147  }
148  $this->object->setThumbGeometry( $_POST["thumb_geometry"] );
149  $this->object->setMatchingMode($_POST['matching_mode']);
150  }
151 
152  public function uploadterms()
153  {
154  $this->writePostData(true);
155  $this->editQuestion();
156  }
157 
158  public function removeimageterms()
159  {
160  $this->writePostData(true);
161  $position = key($_POST['cmd']['removeimageterms']);
162  $this->object->removeTermImage($position);
163  $this->editQuestion();
164  }
165 
166  public function uploaddefinitions()
167  {
168  $this->writePostData(true);
169  $this->editQuestion();
170  }
171 
172  public function removeimagedefinitions()
173  {
174  $this->writePostData(true);
175  $position = key($_POST['cmd']['removeimagedefinitions']);
176  $this->object->removeDefinitionImage($position);
177  $this->editQuestion();
178  }
179 
180  public function addterms()
181  {
182  $this->writePostData();
183  $position = key($_POST["cmd"]["addterms"]);
184  $this->object->insertTerm($position+1);
185  $this->editQuestion();
186  }
187 
188  public function removeterms()
189  {
190  $this->writePostData();
191  $position = key($_POST["cmd"]["removeterms"]);
192  $this->object->deleteTerm($position);
193  $this->editQuestion();
194  }
195 
196  public function adddefinitions()
197  {
198  $this->writePostData();
199  $position = key($_POST["cmd"]["adddefinitions"]);
200  $this->object->insertDefinition($position+1);
201  $this->editQuestion();
202  }
203 
204  public function removedefinitions()
205  {
206  $this->writePostData();
207  $position = key($_POST["cmd"]["removedefinitions"]);
208  $this->object->deleteDefinition($position);
209  $this->editQuestion();
210  }
211 
212  public function addpairs()
213  {
214  $this->writePostData();
215  $position = key($_POST["cmd"]["addpairs"]);
216  $this->object->insertMatchingPair($position+1);
217  $this->editQuestion();
218  }
219 
220  public function removepairs()
221  {
222  $this->writePostData();
223  $position = key($_POST["cmd"]["removepairs"]);
224  $this->object->deleteMatchingPair($position);
225  $this->editQuestion();
226  }
227 
228  public function editQuestion($checkonly = FALSE)
229  {
230  $save = $this->isSaveCommand();
231  $this->getQuestionTemplate();
232 
233  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
234  $form = new ilPropertyFormGUI();
235  $this->editForm = $form;
236 
237  $form->setFormAction($this->ctrl->getFormAction($this));
238  $form->setTitle($this->outQuestionType());
239  $form->setMultipart(true);
240  $form->setTableWidth("100%");
241  $form->setId("matching");
242 
243 
244  // title, author, description, question, working time (assessment mode)
245  $this->addBasicQuestionFormProperties($form);
246  $this->populateQuestionSpecificFormPart( $form );
247  $this->populateAnswerSpecificFormPart( $form );
248  $this->populateTaxonomyFormSection($form);
249  $this->addQuestionFormCommandButtons($form);
250 
251  $errors = false;
252  if ($save)
253  {
254  $form->setValuesByPost();
255  $errors = !$form->checkInput();
256  $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
257  if( !$errors && !$this->isValidTermAndDefinitionAmount($form) && !$this->object->getSelfAssessmentEditingMode() )
258  {
259  $errors = true;
260  $terms = $form->getItemByPostVar('terms');
261  $terms->setAlert($this->lng->txt("msg_number_of_terms_too_low"));
262  ilUtil::sendFailure($this->lng->txt('form_input_not_valid'));
263  }
264  if ($errors) $checkonly = false;
265  }
266 
267  if (!$checkonly) $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
268  return $errors;
269  }
270 
271  private function isDefImgUploadCommand()
272  {
273  return $this->ctrl->getCmd() == 'uploaddefinitions';
274  }
275 
276  private function isTermImgUploadCommand()
277  {
278  return $this->ctrl->getCmd() == 'uploadterms';
279  }
280 
289  {
290  $matchingMode = $form->getItemByPostVar('matching_mode')->getValue();
291 
292  if( $matchingMode == assMatchingQuestion::MATCHING_MODE_N_ON_N )
293  {
294  return true;
295  }
296 
297  $numTerms = count($form->getItemByPostVar('terms')->getValues());
298  $numDefinitions = count($form->getItemByPostVar('definitions')->getValues());
299 
300  if($numTerms >= $numDefinitions)
301  {
302  return true;
303  }
304 
305  return false;
306  }
307 
309  {
310  // Definitions
311  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
312  $definitions = new ilMatchingWizardInputGUI($this->lng->txt( "definitions" ), "definitions");
313  if ($this->object->getSelfAssessmentEditingMode())
314  {
315  $definitions->setHideImages( true );
316  }
317 
318  $definitions->setRequired( true );
319  $definitions->setQuestionObject( $this->object );
320  $definitions->setTextName( $this->lng->txt( 'definition_text' ) );
321  $definitions->setImageName( $this->lng->txt( 'definition_image' ) );
322  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
323  if (!count( $this->object->getDefinitions() ))
324  {
325  $this->object->addDefinition( new assAnswerMatchingDefinition() );
326  }
327  $definitionvalues = $this->object->getDefinitions();
328  $definitions->setValues( $definitionvalues );
329  if( $this->isDefImgUploadCommand() )
330  {
331  $definitions->checkInput();
332  }
333  $form->addItem( $definitions );
334 
335  // Terms
336  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingWizardInputGUI.php";
337  $terms = new ilMatchingWizardInputGUI($this->lng->txt( "terms" ), "terms");
338  if ($this->object->getSelfAssessmentEditingMode())
339  $terms->setHideImages( true );
340  $terms->setRequired( true );
341  $terms->setQuestionObject( $this->object );
342  $terms->setTextName( $this->lng->txt( 'term_text' ) );
343  $terms->setImageName( $this->lng->txt( 'term_image' ) );
344  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
345  if (!count( $this->object->getTerms() ))
346  $this->object->addTerm( new assAnswerMatchingTerm() );
347  $termvalues = $this->object->getTerms();
348  $terms->setValues( $termvalues );
349  if( $this->isTermImgUploadCommand() )
350  {
351  $terms->checkInput();
352  }
353  $form->addItem( $terms );
354 
355  // Matching Pairs
356  include_once "./Modules/TestQuestionPool/classes/class.ilMatchingPairWizardInputGUI.php";
357  $pairs = new ilMatchingPairWizardInputGUI($this->lng->txt( 'matching_pairs' ), 'pairs');
358  $pairs->setRequired( true );
359  $pairs->setTerms( $this->object->getTerms() );
360  $pairs->setDefinitions( $this->object->getDefinitions() );
361  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
362  if (count( $this->object->getMatchingPairs() ) == 0)
363  {
364  $this->object->addMatchingPair( new assAnswerMatchingPair($termvalues[0], $definitionvalues[0], 0) );
365  }
366  $pairs->setPairs( $this->object->getMatchingPairs() );
367  $form->addItem( $pairs );
368 
369  return $form;
370  }
371 
373  {
374  // Edit mode
375  $hidden = new ilHiddenInputGUI("matching_type");
376  $hidden->setValue($matchingtype);
377  $form->addItem($hidden);
378 
379  if (!$this->object->getSelfAssessmentEditingMode())
380  {
381  // shuffle
382  $shuffle = new ilSelectInputGUI($this->lng->txt( "shuffle_answers" ), "shuffle");
383  $shuffle_options = array(
384  0 => $this->lng->txt( "no" ),
385  1 => $this->lng->txt( "matching_shuffle_terms_definitions" ),
386  2 => $this->lng->txt( "matching_shuffle_terms" ),
387  3 => $this->lng->txt( "matching_shuffle_definitions" )
388  );
389  $shuffle->setOptions( $shuffle_options );
390  $shuffle->setValue($this->object->getShuffle() != null ? $this->object->getShuffle() : 1);
391  $shuffle->setRequired( FALSE );
392  $form->addItem( $shuffle );
393 
394  $geometry = new ilNumberInputGUI($this->lng->txt( "thumb_geometry" ), "thumb_geometry");
395  $geometry->setValue( $this->object->getThumbGeometry() );
396  $geometry->setRequired( true );
397  $geometry->setMaxLength( 6 );
398  $geometry->setMinValue( 20 );
399  $geometry->setSize( 6 );
400  $geometry->setInfo( $this->lng->txt( "thumb_geometry_info" ) );
401  $form->addItem( $geometry );
402  }
403 
404  // Matching Mode
405  $mode = new ilRadioGroupInputGUI($this->lng->txt('qpl_qst_inp_matching_mode'), 'matching_mode');
406  $mode->setRequired(true);
407 
408  $modeONEonONE = new ilRadioOption(
409  $this->lng->txt('qpl_qst_inp_matching_mode_one_on_one'), assMatchingQuestion::MATCHING_MODE_1_ON_1
410  );
411  $mode->addOption($modeONEonONE);
412 
413  $modeALLonALL = new ilRadioOption(
414  $this->lng->txt('qpl_qst_inp_matching_mode_all_on_all'), assMatchingQuestion::MATCHING_MODE_N_ON_N
415  );
416  $mode->addOption($modeALLonALL);
417 
418  $mode->setValue($this->object->getMatchingMode());
419 
420  $form->addItem($mode);
421  }
422 
437  $active_id,
438  $pass = NULL,
439  $graphicalOutput = FALSE,
440  $result_output = FALSE,
441  $show_question_only = TRUE,
442  $show_feedback = FALSE,
443  $show_correct_solution = FALSE,
444  $show_manual_scoring = FALSE,
445  $show_question_text = TRUE
446  )
447  {
448  // generate the question output
449  include_once "./Services/UICore/classes/class.ilTemplate.php";
450  $template = new ilTemplate("tpl.il_as_qpl_matching_output_solution.html", TRUE, TRUE, "Modules/TestQuestionPool");
451  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html",TRUE, TRUE, "Modules/TestQuestionPool");
452 
453  $solutions = array();
454  if (($active_id > 0) && (!$show_correct_solution))
455  {
456  include_once "./Modules/Test/classes/class.ilObjTest.php";
457  $solutions =& $this->object->getSolutionValues($active_id, $pass);
458  $solution_script .= "";
459  }
460  else
461  {
462  foreach ($this->object->getMaximumScoringMatchingPairs() as $pair)
463  {
464  $solutions[] = array(
465  "value1" => $pair->term->identifier,
466  "value2" => $pair->definition->identifier,
467  'points' => $pair->points
468  );
469  }
470  }
471 
472  $i = 0;
473 
474  foreach ($solutions as $solution)
475  {
476  $definition = $this->object->getDefinitionWithIdentifier($solution['value2']);
477  $term = $this->object->getTermWithIdentifier($solution['value1']);
478  $points = $solution['points'];
479 
480  if (is_object($definition))
481  {
482  if (strlen($definition->picture))
483  {
484  if( strlen($definition->text) )
485  {
486  $template->setCurrentBlock('definition_image_text');
487  $template->setVariable("TEXT_DEFINITION", ilUtil::prepareFormOutput($definition->text));
488  $template->parseCurrentBlock();
489  }
490 
491  require_once 'Services/WebAccessChecker/classes/class.ilWACSignedPath.php';
492  $answerImageSrc = ilWACSignedPath::signFile(
493  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture
494  );
495 
496  $template->setCurrentBlock('definition_image');
497  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
498  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
499  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($definition->text)) ? ilUtil::prepareFormOutput($definition->text) : ilUtil::prepareFormOutput($definition->picture));
500  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $definition->picture);
501  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
502  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
503  $template->parseCurrentBlock();
504  }
505  else
506  {
507  $template->setCurrentBlock('definition_text');
508  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, TRUE));
509  $template->parseCurrentBlock();
510  }
511  }
512  if (is_object($term))
513  {
514  if (strlen($term->picture))
515  {
516  if( strlen($term->text) )
517  {
518  $template->setCurrentBlock('term_image_text');
519  $template->setVariable("TEXT_TERM", ilUtil::prepareFormOutput($term->text));
520  $template->parseCurrentBlock();
521  }
522 
523  require_once 'Services/WebAccessChecker/classes/class.ilWACSignedPath.php';
524  $answerImageSrc = ilWACSignedPath::signFile(
525  $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture
526  );
527 
528  $template->setCurrentBlock('term_image');
529  $template->setVariable('ANSWER_IMAGE_URL', $answerImageSrc);
530  $template->setVariable('ANSWER_IMAGE_ALT', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
531  $template->setVariable('ANSWER_IMAGE_TITLE', (strlen($term->text)) ? ilUtil::prepareFormOutput($term->text) : ilUtil::prepareFormOutput($term->picture));
532  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $term->picture);
533  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
534  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
535  $template->parseCurrentBlock();
536  }
537  else
538  {
539  $template->setCurrentBlock('term_text');
540  $template->setVariable("TERM", $this->object->prepareTextareaOutput($term->text, TRUE));
541  $template->parseCurrentBlock();
542  }
543  $i++;
544  }
545  if (($active_id > 0) && (!$show_correct_solution))
546  {
547  if ($graphicalOutput)
548  {
549  // output of ok/not ok icons for user entered solutions
550  $ok = false;
551  foreach ($this->object->getMatchingPairs() as $pair)
552  {
553  if( $this->isCorrectMatching($pair, $definition, $term) )
554  {
555  $ok = true;
556  }
557  }
558 
559  if ($ok)
560  {
561  $template->setCurrentBlock("icon_ok");
562  $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
563  $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
564  $template->parseCurrentBlock();
565  }
566  else
567  {
568  $template->setCurrentBlock("icon_ok");
569  $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
570  $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
571  $template->parseCurrentBlock();
572  }
573  }
574  }
575 
576  if ($result_output)
577  {
578  $resulttext = ($points == 1) ? "(%s " . $this->lng->txt("point") . ")" : "(%s " . $this->lng->txt("points") . ")";
579  $template->setCurrentBlock("result_output");
580  $template->setVariable("RESULT_OUTPUT", sprintf($resulttext, $points));
581  $template->parseCurrentBlock();
582  }
583 
584  $template->setCurrentBlock("row");
585  $template->setVariable("TEXT_MATCHES", $this->lng->txt("matches"));
586  $template->parseCurrentBlock();
587  }
588 
589  $questiontext = $this->object->getQuestion();
590  if ($show_question_text==true)
591  {
592  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, TRUE));
593  }
594 
595  $questionoutput = $template->get();
596 
597  $feedback = '';
598  if($show_feedback)
599  {
600  if( !$this->isTestPresentationContext() )
601  {
602  $fb = $this->getGenericFeedbackOutput($active_id, $pass);
603  $feedback .= strlen($fb) ? $fb : '';
604  }
605 
606  $fb = $this->getSpecificFeedbackOutput($active_id, $pass);
607  $feedback .= strlen($fb) ? $fb : '';
608  }
609  if (strlen($feedback))
610  {
611  $cssClass = ( $this->hasCorrectSolution($active_id, $pass) ?
613  );
614 
615  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
616  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput( $feedback, true ));
617  }
618 
619  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
620 
621  $solutionoutput = $solutiontemplate->get();
622  if (!$show_question_only)
623  {
624  // get page object output
625  $solutionoutput = $this->getILIASPage($solutionoutput);
626  }
627  return $solutionoutput;
628  }
629 
630  public function getPreview($show_question_only = FALSE, $showInlineFeedback = false)
631  {
632  $solutions = is_object($this->getPreviewSession()) ? (array)$this->getPreviewSession()->getParticipantsSolution() : array();
633 
634  if($GLOBALS['ilBrowser']->isMobile() || $GLOBALS['ilBrowser']->isIpad())
635  {
636  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
639  $this->tpl->addJavaScript('./Services/jQuery/js/jquery.ui.touch-punch.min.js');
640  }
641  else
642  {
643  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/jquery-ui-1-10-3-fixed.js');
644  }
645  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
646  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
647 
648  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", TRUE, TRUE, "Modules/TestQuestionPool");
649 
650  foreach($solutions as $defId => $terms)
651  {
652  foreach($terms as $termId)
653  {
654  $template->setCurrentBlock("matching_data");
655  $template->setVariable("DEFINITION_ID", $defId);
656  $template->setVariable("TERM_ID", $termId);
657  $template->parseCurrentBlock();
658  }
659  }
660 
661  // shuffle output
662  $terms = $this->object->getTerms();
663  $definitions = $this->object->getDefinitions();
664  switch ($this->object->getShuffle())
665  {
666  case 1:
667  $seed = $this->object->getShuffler()->getSeed();
668  $this->object->getShuffler()->setSeed($seed.'1');
669  $terms = $this->object->getShuffler()->shuffle($terms);
670  $this->object->getShuffler()->setSeed($seed.'2');
671  $definitions = $this->object->getShuffler()->shuffle($definitions);
672  $this->object->getShuffler()->setSeed($seed);
673  break;
674  case 2:
675  $terms = $this->object->getShuffler()->shuffle($terms);
676  break;
677  case 3:
678  $definitions = $this->object->getShuffler()->shuffle($definitions);
679  break;
680  }
681 
682  // create definitions
683  $counter = 0;
684  foreach ($definitions as $definition)
685  {
686  if (strlen($definition->picture))
687  {
688  $template->setCurrentBlock("definition_picture");
689  $template->setVariable("DEFINITION_ID", $definition->identifier);
690  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
691  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
692  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->picture;
693  if (!@file_exists($thumb)) $this->object->rebuildThumbnails();
694  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
695  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
696  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
697  $template->setVariable("TEXT_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, TRUE, true) : '');
698  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
699  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
700  $template->parseCurrentBlock();
701  }
702  else
703  {
704  $template->setCurrentBlock("definition_text");
705  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, TRUE, true));
706  $template->parseCurrentBlock();
707  }
708 
709  $template->setCurrentBlock("droparea");
710  $template->setVariable("ID_DROPAREA", $definition->identifier);
711  $template->setVariable("QUESTION_ID", $this->object->getId());
712  $template->parseCurrentBlock();
713 
714  $template->setCurrentBlock("definition_data");
715  $template->setVariable("DEFINITION_ID", $definition->identifier);
716  $template->parseCurrentBlock();
717  }
718 
719  // create terms
720  $counter = 0;
721  foreach ($terms as $term)
722  {
723  if (strlen($term->picture))
724  {
725  $template->setCurrentBlock("term_picture");
726  $template->setVariable("TERM_ID", $term->identifier);
727  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
728  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
729  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
730  if (!@file_exists($thumb)) $this->object->rebuildThumbnails();
731  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
732  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
733  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
734  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
735  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, TRUE, true) : '');
736  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
737  $template->parseCurrentBlock();
738  }
739  else
740  {
741  $template->setCurrentBlock("term_text");
742  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, TRUE, true));
743  $template->parseCurrentBlock();
744  }
745  $template->setCurrentBlock("draggable");
746  $template->setVariable("ID_DRAGGABLE", $term->identifier);
747  $template->parseCurrentBlock();
748 
749  $template->setCurrentBlock("term_data");
750  $template->setVariable("TERM_ID", $term->identifier);
751  $template->parseCurrentBlock();
752  }
753 
754  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
755 
756  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
757 
758  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), TRUE));
759 
760  $questionoutput = $template->get();
761 
762  if (!$show_question_only)
763  {
764  // get page object output
765  $questionoutput = $this->getILIASPage($questionoutput);
766  }
767 
768  return $questionoutput;
769  }
770 
776  protected function sortDefinitionsBySolution(array $solution, array $definitions)
777  {
778  $neworder = array();
779  $handled_defintions = array();
780  foreach($solution as $solution_values)
781  {
782  $id = $solution_values['value2'];
783  if(!isset($handled_defintions[$id]))
784  {
785  $neworder[] = $this->object->getDefinitionWithIdentifier($id);
786  $handled_defintions[$id] = $id;
787  }
788  }
789 
790  foreach($definitions as $definition)
791  {
795  if(!isset($handled_defintions[$definition->identifier]))
796  {
797  $neworder[] = $definition;
798  }
799  }
800 
801  return $neworder;
802  }
803 
804  // hey: prevPassSolutions - pass will be always available from now on
805  function getTestOutput($active_id, $pass, $is_postponed = FALSE, $user_post_solution = FALSE, $inlineFeedback = false)
806  // hey.
807  {
808  if($GLOBALS['ilBrowser']->isMobile() || $GLOBALS['ilBrowser']->isIpad())
809  {
810  require_once 'Services/jQuery/classes/class.iljQueryUtil.php';
813  $this->tpl->addJavaScript('./Services/jQuery/js/jquery.ui.touch-punch.min.js');
814  }
815  else
816  {
817  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/jquery-ui-1-10-3-fixed.js');
818  }
819  $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilMatchingQuestion.js');
820  $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_javascript.css', 'Modules/TestQuestionPool'));
821 
822  $template = new ilTemplate("tpl.il_as_qpl_matching_output.html", true, true, "Modules/TestQuestionPool");
823 
824  if ($active_id)
825  {
826  // hey: prevPassSolutions - obsolete due to central check
827  #$solutions = NULL;
828  #include_once "./Modules/Test/classes/class.ilObjTest.php";
829  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
830  #{
831  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
832  #}
833  // hey.
834  if (is_array($user_post_solution))
835  {
836  $solutions = array();
837  foreach ($user_post_solution['matching'][$this->object->getId()] as $definition => $term)
838  {
839  array_push($solutions, array("value1" => $term, "value2" => $definition));
840  }
841  }
842  else
843  {
844  // hey: prevPassSolutions - obsolete due to central check
845  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
846  // hey.
847  }
848 
849  $counter = 0;
850  foreach ($solutions as $idx => $solution_value)
851  {
852  if (($solution_value["value2"] > -1) && ($solution_value["value1"] > -1))
853  {
854  $template->setCurrentBlock("matching_data");
855  $template->setVariable("TERM_ID", $solution_value["value1"]);
856  $template->setVariable("DEFINITION_ID", $solution_value["value2"]);
857  $template->parseCurrentBlock();
858  }
859 
860  $counter++;
861  }
862  }
863 
864  $terms = $this->object->getTerms();
865  $definitions = $this->object->getDefinitions();
866  switch ($this->object->getShuffle())
867  {
868  case 1:
869  $seed = $this->object->getShuffler()->getSeed();
870  $this->object->getShuffler()->setSeed($seed.'1');
871  $terms = $this->object->getShuffler()->shuffle($terms);
872  if (count($solutions))
873  {
874  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
875  }
876  else
877  {
878  $this->object->getShuffler()->setSeed($seed.'2');
879  $definitions = $this->object->getShuffler()->shuffle($definitions);
880  }
881  $this->object->getShuffler()->setSeed($seed);
882  break;
883  case 2:
884  $terms = $this->object->getShuffler()->shuffle($terms);
885  break;
886  case 3:
887  if (count($solutions))
888  {
889  $definitions = $this->sortDefinitionsBySolution($solutions, $definitions);
890  }
891  else
892  {
893  $definitions = $this->object->getShuffler()->shuffle($definitions);
894  }
895  break;
896  }
897 
898  // create definitions
899  $counter = 0;
900  foreach ($definitions as $definition)
901  {
902  if (strlen($definition->picture))
903  {
904  $template->setCurrentBlock("definition_picture");
905  $template->setVariable("DEFINITION_ID", $definition->identifier);
906  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $definition->picture);
907  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $definition->picture;
908  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $definition->picture;
909  if (!@file_exists($thumb)) $this->object->rebuildThumbnails();
910  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
911  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
912  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
913  $template->setVariable("TEXT_DEFINITION", (strlen($definition->text)) ? $this->object->prepareTextareaOutput($definition->text, true, true) : '');
914  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
915  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
916  $template->parseCurrentBlock();
917  }
918  else
919  {
920  $template->setCurrentBlock("definition_text");
921  $template->setVariable("DEFINITION", $this->object->prepareTextareaOutput($definition->text, true, true));
922  $template->parseCurrentBlock();
923  }
924 
925  $template->setCurrentBlock("droparea");
926  $template->setVariable("ID_DROPAREA", $definition->identifier);
927  $template->setVariable("QUESTION_ID", $this->object->getId());
928  $template->parseCurrentBlock();
929 
930  $template->setCurrentBlock("definition_data");
931  $template->setVariable("DEFINITION_ID", $definition->identifier);
932  $template->parseCurrentBlock();
933  }
934 
935  // create terms
936  $counter = 0;
937  foreach ($terms as $term)
938  {
939  if (strlen($term->picture))
940  {
941  $template->setCurrentBlock("term_picture");
942  $template->setVariable("TERM_ID", $term->identifier);
943  $template->setVariable("IMAGE_HREF", $this->object->getImagePathWeb() . $term->picture);
944  $thumbweb = $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $term->picture;
945  $thumb = $this->object->getImagePath() . $this->object->getThumbPrefix() . $term->picture;
946  if (!@file_exists($thumb)) $this->object->rebuildThumbnails();
947  $template->setVariable("THUMBNAIL_HREF", $thumbweb);
948  $template->setVariable("THUMB_ALT", $this->lng->txt("image"));
949  $template->setVariable("THUMB_TITLE", $this->lng->txt("image"));
950  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
951  $template->setVariable("TEXT_TERM", (strlen($term->text)) ? $this->object->prepareTextareaOutput($term->text, true, true) : '');
952  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
953  $template->parseCurrentBlock();
954  }
955  else
956  {
957  $template->setCurrentBlock("term_text");
958  $template->setVariable("TERM_TEXT", $this->object->prepareTextareaOutput($term->text, true, true));
959  $template->parseCurrentBlock();
960  }
961  $template->setCurrentBlock("draggable");
962  $template->setVariable("ID_DRAGGABLE", $term->identifier);
963  $template->parseCurrentBlock();
964 
965  $template->setCurrentBlock('term_data');
966  $template->setVariable('TERM_ID', $term->identifier);
967  $template->parseCurrentBlock();
968  }
969 
970  $template->setVariable('MATCHING_MODE', $this->object->getMatchingMode());
971 
972  $template->setVariable("RESET_BUTTON", $this->lng->txt("reset_terms"));
973 
974  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($this->object->getQuestion(), TRUE));
975 
976  return $this->outQuestionPage("", $is_postponed, $active_id, $template->get());
977  }
978 
982  function checkInput()
983  {
984  if ((!$_POST["title"]) or (!$_POST["author"]) or (!$_POST["question"]))
985  {
986  return false;
987  }
988  return true;
989  }
990 
998  function setQuestionTabs()
999  {
1000  global $rbacsystem, $ilTabs;
1001 
1002  $ilTabs->clearTargets();
1003 
1004  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
1005  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1006  $q_type = $this->object->getQuestionType();
1007 
1008  if (strlen($q_type))
1009  {
1010  $classname = $q_type . "GUI";
1011  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
1012  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
1013  }
1014 
1015  if ($_GET["q_id"])
1016  {
1017  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
1018  {
1019  // edit page
1020  $ilTabs->addTarget("edit_page",
1021  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
1022  array("edit", "insert", "exec_pg"),
1023  "", "", $force_active);
1024  }
1025 
1026  $this->addTab_QuestionPreview($ilTabs);
1027  }
1028 
1029  $force_active = false;
1030  if ($rbacsystem->checkAccess('write', $_GET["ref_id"]))
1031  {
1032  $url = "";
1033  if ($classname) $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
1034  // edit question properties
1035  $ilTabs->addTarget("edit_question",
1036  $url,
1037  array("editQuestion", "save", "saveEdit", "removeimageterms", "uploadterms", "removeimagedefinitions", "uploaddefinitions",
1038  "addpairs", "removepairs", "addterms", "removeterms", "adddefinitions", "removedefinitions", "originalSyncForm"),
1039  $classname, "", $force_active);
1040  }
1041 
1042  // add tab for question feedback within common class assQuestionGUI
1043  $this->addTab_QuestionFeedback($ilTabs);
1044 
1045  // add tab for question hint within common class assQuestionGUI
1046  $this->addTab_QuestionHints($ilTabs);
1047 
1048  // add tab for question's suggested solution within common class assQuestionGUI
1049  $this->addTab_SuggestedSolution($ilTabs, $classname);
1050 
1051  // Assessment of questions sub menu entry
1052  if ($_GET["q_id"])
1053  {
1054  $ilTabs->addTarget("statistics",
1055  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
1056  array("assessment"),
1057  $classname, "");
1058  }
1059 
1060  $this->addBackTab($ilTabs);
1061  }
1062 
1063  function getSpecificFeedbackOutput($active_id, $pass)
1064  {
1065  $userSolution = $this->object->fetchIndexedValuesFromValuePairs(
1066  $this->object->getSolutionValues($active_id, $pass)
1067  );
1068 
1069  $matches = array_values($this->object->matchingpairs);
1070 
1071  if( !$this->object->feedbackOBJ->specificAnswerFeedbackExists($matches) )
1072  {
1073  return '';
1074  }
1075 
1076  $feedback = '<table class="test_specific_feedback"><tbody>';
1077 
1078  foreach ($matches as $idx => $ans)
1079  {
1080  if($active_id)
1081  {
1082  if( !isset($userSolution[$ans->definition->identifier]) )
1083  {
1084  continue;
1085  }
1086 
1087  if( !is_array($userSolution[$ans->definition->identifier]) )
1088  {
1089  continue;
1090  }
1091 
1092  if( !in_array($ans->term->identifier, $userSolution[$ans->definition->identifier]) )
1093  {
1094  continue;
1095  }
1096  }
1097 
1098  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
1099  $this->object->getId(), $idx
1100  );
1101  $feedback .= '<tr><td>"' . $ans->definition->text . '"&nbsp;' . $this->lng->txt("matches") . '&nbsp;"';
1102  $feedback .= $ans->term->text . '"</td><td>';
1103  $feedback .= $fb . '</td> </tr>';
1104  }
1105 
1106  $feedback .= '</tbody></table>';
1107  return $this->object->prepareTextareaOutput($feedback, TRUE);
1108  }
1109 
1120  {
1121  return array();
1122  }
1123 
1134  {
1135  return array();
1136  }
1137 
1146  public function getAggregatedAnswersView($relevant_answers)
1147  {
1148  return ''; //print_r($relevant_answers,true);
1149  }
1150 
1151  private function isCorrectMatching($pair, $definition, $term)
1152  {
1153  if( !($pair->points > 0) )
1154  {
1155  return false;
1156  }
1157 
1158  if( !is_object($term) )
1159  {
1160  return false;
1161  }
1162 
1163  if( $pair->definition->identifier != $definition->identifier )
1164  {
1165  return false;
1166  }
1167 
1168  if( $pair->term->identifier != $term->identifier )
1169  {
1170  return false;
1171  }
1172 
1173  return true;
1174  }
1175 }
Class for matching question terms.
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms public
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
This class represents an option in a radio group.
static initjQueryUI()
Init jQuery UI (see included_components.txt for included components)
Class for matching question pairs.
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question, working time.
getItemByPostVar($a_post_var)
Get Item by POST variable.
setValue($a_value)
Set Value.
This class represents a single choice wizard property in a property form.
This class represents a selection list property in a property form.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
setHideImages($a_hide)
Set hide images.
This class represents a property form user interface.
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
$_GET["client_id"]
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
isValidTermAndDefinitionAmount(ilPropertyFormGUI $form)
for mode 1:1 terms count must not be less than definitions count for mode n:n this limitation is canc...
addItem($a_item)
Add Item (Property, SectionHeader).
$url
Definition: shib_logout.php:72
getQuestionTemplate()
get question template
Matching question GUI representation.
populateTaxonomyFormSection(ilPropertyFormGUI $form)
Class for matching questions.
getPreview($show_question_only=FALSE, $showInlineFeedback=false)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
$counter
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
This class represents a hidden form property in a property form.
This class represents a property in a property form.
setValue($a_value)
Set Value.
__construct($id=-1)
assMatchingQuestionGUI constructor
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
getILIASPage($html="")
Returns the ILIAS Page around a question.
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.
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
special template class to simplify handling of ITX/PEAR
isCorrectMatching($pair, $definition, $term)
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
static signFile($path_to_file)
Basic GUI class for assessment questions.
setErrorMessage($errormessage)
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
Create styles array
The data for the language used.
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
setQuestionTabs()
Sets the ILIAS tabs for this question type.
$errors
Create new PHPExcel object
obj_idprivate
addBackTab(ilTabsGUI $ilTabs)
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.
Class for matching question definitions.
static initjQuery($a_tpl=null)
Init jQuery.
Interface ilGuiAnswerScoringAdjustable.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="")
output question page
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Interface ilGuiQuestionScoringAdjustable.
getTestOutput($active_id, $pass, $is_postponed=FALSE, $user_post_solution=FALSE, $inlineFeedback=false)
$_POST["username"]
setRequired($a_required)
Set Required.
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
This class represents a key value pair wizard property in a property form.
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.