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