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