소스 검색

Merge pull request #2970 from chamilo/immediate_popup

New exercise type: immediate popup BT#15827
Julio Montoya 5 년 전
부모
커밋
2277d1515e
36개의 변경된 파일610개의 추가작업 그리고 981개의 파일을 삭제
  1. 2 2
      main/exercise/Annotation.php
  2. 2 2
      main/exercise/Draggable.php
  3. 20 0
      main/exercise/HotSpotDelineation.php
  4. 2 2
      main/exercise/MatchingDraggable.php
  5. 2 2
      main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php
  6. 2 2
      main/exercise/ReadingComprehension.php
  7. 2 3
      main/exercise/UniqueAnswerImage.php
  8. 2 2
      main/exercise/calculated_answer.class.php
  9. 296 180
      main/exercise/exercise.class.php
  10. 1 9
      main/exercise/exercise.php
  11. 13 34
      main/exercise/exercise_result.php
  12. 3 147
      main/exercise/exercise_show.php
  13. 8 13
      main/exercise/exercise_submit.php
  14. 149 431
      main/exercise/exercise_submit_modal.php
  15. 2 2
      main/exercise/fill_blanks.class.php
  16. 2 2
      main/exercise/freeanswer.class.php
  17. 2 2
      main/exercise/global_multiple_answer.class.php
  18. 2 49
      main/exercise/hotspot.class.php
  19. 2 2
      main/exercise/matching.class.php
  20. 2 2
      main/exercise/multiple_answer.class.php
  21. 2 2
      main/exercise/multiple_answer_combination.class.php
  22. 2 2
      main/exercise/multiple_answer_combination_true_false.class.php
  23. 2 2
      main/exercise/multiple_answer_true_false.class.php
  24. 2 2
      main/exercise/oral_expression.class.php
  25. 1 4
      main/exercise/overview.php
  26. 40 34
      main/exercise/question.class.php
  27. 1 1
      main/exercise/question_admin.inc.php
  28. 2 2
      main/exercise/question_create.php
  29. 5 3
      main/exercise/question_list_admin.inc.php
  30. 6 4
      main/exercise/question_pool.php
  31. 5 11
      main/exercise/unique_answer.class.php
  32. 2 2
      main/exercise/unique_answer_no_option.class.php
  33. 2 4
      main/inc/ajax/exercise.ajax.php
  34. 0 1
      main/inc/lib/exercise.lib.php
  35. 17 13
      main/inc/lib/geometry.lib.php
  36. 5 6
      main/inc/lib/internationalization.lib.php

+ 2 - 2
main/exercise/Annotation.php

@@ -11,8 +11,8 @@
  */
 class Annotation extends Question
 {
-    public static $typePicture = 'annotation.png';
-    public static $explanationLangVar = 'Annotation';
+    public $typePicture = 'annotation.png';
+    public $explanationLangVar = 'Annotation';
 
     /**
      * Annotation constructor.

+ 2 - 2
main/exercise/Draggable.php

@@ -8,8 +8,8 @@
  */
 class Draggable extends Question
 {
-    public static $typePicture = 'ordering.png';
-    public static $explanationLangVar = 'Draggable';
+    public $typePicture = 'ordering.png';
+    public $explanationLangVar = 'Draggable';
 
     /**
      * Class constructor.

+ 20 - 0
main/exercise/HotSpotDelineation.php

@@ -0,0 +1,20 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Class HotSpotDelineation.
+ */
+class HotSpotDelineation extends HotSpot
+{
+    public $typePicture = 'hotspot-delineation.png';
+    public $explanationLangVar = 'HotspotDelineation';
+
+    /**
+     * HotSpotDelineation constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->type = HOT_SPOT_DELINEATION;
+    }
+}

+ 2 - 2
main/exercise/MatchingDraggable.php

@@ -8,8 +8,8 @@
  */
 class MatchingDraggable extends Question
 {
-    public static $typePicture = 'matchingdrag.png';
-    public static $explanationLangVar = 'MatchingDraggable';
+    public $typePicture = 'matchingdrag.png';
+    public $explanationLangVar = 'MatchingDraggable';
 
     /**
      * Class constructor.

+ 2 - 2
main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php

@@ -18,8 +18,8 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question
     const LEVEL_LIGHTRED = 4;
     const LEVEL_DARKRED = 5;
 
-    public static $typePicture = 'mccert.png';
-    public static $explanationLangVar = 'MultipleAnswerTrueFalseDegreeCertainty';
+    public $typePicture = 'mccert.png';
+    public $explanationLangVar = 'MultipleAnswerTrueFalseDegreeCertainty';
     public $optionsTitle;
     public $options;
 

+ 2 - 2
main/exercise/ReadingComprehension.php

@@ -11,8 +11,8 @@
  */
 class ReadingComprehension extends UniqueAnswer
 {
-    public static $typePicture = 'reading-comprehension.png';
-    public static $explanationLangVar = 'ReadingComprehension';
+    public $typePicture = 'reading-comprehension.png';
+    public $explanationLangVar = 'ReadingComprehension';
 
     /**
      * Defines the different speeds of scrolling for the reading window,

+ 2 - 3
main/exercise/UniqueAnswerImage.php

@@ -10,8 +10,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswerImage extends UniqueAnswer
 {
-    public static $typePicture = 'uaimg.png';
-    public static $explanationLangVar = 'UniqueAnswerImage';
+    public $typePicture = 'uaimg.png';
+    public $explanationLangVar = 'UniqueAnswerImage';
 
     /**
      * UniqueAnswerImage constructor.
@@ -119,7 +119,6 @@ class UniqueAnswerImage extends UniqueAnswer
         }
 
         $tempScenario = [];
-
         if ($numberAnswers < 1) {
             $numberAnswers = 1;
             echo Display::return_message(get_lang('YouHaveToCreateAtLeastOneAnswer'));

+ 2 - 2
main/exercise/calculated_answer.class.php

@@ -13,8 +13,8 @@ use Webit\Util\EvalMath\EvalMath;
  */
 class CalculatedAnswer extends Question
 {
-    public static $typePicture = 'calculated_answer.png';
-    public static $explanationLangVar = 'CalculatedAnswer';
+    public $typePicture = 'calculated_answer.png';
+    public $explanationLangVar = 'CalculatedAnswer';
 
     /**
      * Constructor.

+ 296 - 180
main/exercise/exercise.class.php

@@ -3,6 +3,7 @@
 
 use Chamilo\CoreBundle\Entity\GradebookLink;
 use Chamilo\CoreBundle\Entity\TrackEHotspot;
+use Chamilo\CourseBundle\Entity\CExerciseCategory;
 use ChamiloSession as Session;
 use Doctrine\DBAL\Types\Type;
 
@@ -689,7 +690,8 @@ class Exercise
                     }
 
                     // Question type
-                    list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html();
+                    $typeImg = $objQuestionTmp->getTypePicture();
+                    $typeExpl = $objQuestionTmp->getExplanation();
 
                     $question_media = null;
                     if (!empty($objQuestionTmp->parent_id)) {
@@ -1939,7 +1941,7 @@ class Exercise
             $categories = $categoryManager->getCategories(api_get_course_int_id());
             $options = [];
             if (!empty($categories)) {
-                /** @var \Chamilo\CourseBundle\Entity\CExerciseCategory $category */
+                /** @var CExerciseCategory $category */
                 foreach ($categories as $category) {
                     $options[$category->getId()] = $category->getName();
                 }
@@ -3070,16 +3072,10 @@ class Exercise
         $weight = 0
     ) {
         $track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
-        $safe_lp_id = intval($safe_lp_id);
-        $safe_lp_item_id = intval($safe_lp_item_id);
-        $safe_lp_item_view_id = intval($safe_lp_item_view_id);
+        $safe_lp_id = (int) $safe_lp_id;
+        $safe_lp_item_id = (int) $safe_lp_item_id;
+        $safe_lp_item_view_id = (int) $safe_lp_item_view_id;
 
-        if (empty($safe_lp_id)) {
-            $safe_lp_id = 0;
-        }
-        if (empty($safe_lp_item_id)) {
-            $safe_lp_item_id = 0;
-        }
         if (empty($clock_expired_time)) {
             $clock_expired_time = null;
         }
@@ -3128,7 +3124,7 @@ class Exercise
         $currentAnswer = '',
         $myRemindList = []
     ) {
-        global $origin, $safe_lp_id, $safe_lp_item_id, $safe_lp_item_view_id;
+        global $safe_lp_id, $safe_lp_item_id, $safe_lp_item_view_id;
         $nbrQuestions = $this->getQuestionCount();
         $buttonList = [];
         $html = $label = '';
@@ -3141,21 +3137,21 @@ class Exercise
             if ($questionNum == count($this->questionList)) {
                 $urlTitle = get_lang('EndTest');
             }
-
+            $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit_modal.php?'.api_get_cidreq();
+            $url .= '&'.http_build_query([
+                'learnpath_id' => $safe_lp_id,
+                'learnpath_item_id' => $safe_lp_item_id,
+                'learnpath_item_view_id' => $safe_lp_item_view_id,
+                'hotspot' => $hotspot_get,
+                'nbrQuestions' => $nbrQuestions,
+                'num' => $questionNum,
+                'exerciseType' => $this->type,
+                'exerciseId' => $this->id,
+                'reminder' => empty($myRemindList) ? null : 2,
+            ]);
             $html .= Display::url(
                 $urlTitle,
-                api_get_path(WEB_CODE_PATH).'exercise/exercise_submit_modal.php?'.http_build_query([
-                    'learnpath_id' => $safe_lp_id,
-                    'learnpath_item_id' => $safe_lp_item_id,
-                    'learnpath_item_view_id' => $safe_lp_item_view_id,
-                    'origin' => $origin,
-                    'hotspot' => $hotspot_get,
-                    'nbrQuestions' => $nbrQuestions,
-                    'num' => $questionNum,
-                    'exerciseType' => $this->type,
-                    'exerciseId' => $this->id,
-                    'reminder' => empty($myRemindList) ? null : 2,
-                ]),
+                $url,
                 [
                     'class' => 'ajax btn btn-default',
                     'data-title' => Security::remove_XSS(get_lang('Comment')),
@@ -3429,6 +3425,7 @@ class Exercise
      * @param array  $hotspot_delineation_result
      * @param bool   $showTotalScoreAndUserChoicesInLastAttempt
      * @param bool   $updateResults
+     * @param bool   $showHotSpotDelineationTable
      *
      * @todo    reduce parameters of this function
      *
@@ -3446,7 +3443,8 @@ class Exercise
         $propagate_neg = 0,
         $hotspot_delineation_result = [],
         $showTotalScoreAndUserChoicesInLastAttempt = true,
-        $updateResults = false
+        $updateResults = false,
+        $showHotSpotDelineationTable = false
     ) {
         $debug = false;
         //needed in order to use in the exercise_attempt() for the time
@@ -3520,7 +3518,6 @@ class Exercise
                 error_log(print_r($extra, 1));
             }
             // Fixes problems with negatives values using intval
-
             $true_score = floatval(trim($extra[0]));
             $false_score = floatval(trim($extra[1]));
             $doubt_score = floatval(trim($extra[2]));
@@ -3601,19 +3598,21 @@ class Exercise
                 ['hotspotAnswerId' => 'ASC']
             );
         }
+        $debug = true;
         if ($debug) {
             error_log('Start answer loop ');
         }
 
+        $answerDestination = null;
         $userAnsweredQuestion = false;
+        $correctAnswerId = null;
         for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
             $answer = $objAnswerTmp->selectAnswer($answerId);
             $answerComment = $objAnswerTmp->selectComment($answerId);
             $answerCorrect = $objAnswerTmp->isCorrect($answerId);
             $answerWeighting = (float) $objAnswerTmp->selectWeighting($answerId);
             $answerAutoId = $objAnswerTmp->selectAutoId($answerId);
-            $answerIid = isset($objAnswerTmp->iid[$answerId]) ? $objAnswerTmp->iid[$answerId] : '';
-            $answer_correct_array[$answerId] = (bool) $answerCorrect;
+            $answerIid = isset($objAnswerTmp->iid[$answerId]) ? (int) $objAnswerTmp->iid[$answerId] : 0;
 
             if ($debug) {
                 error_log("answer auto id: $answerAutoId ");
@@ -3643,13 +3642,15 @@ class Exercise
                         $studentChoice = $choice == $answerAutoId ? 1 : 0;
                         if ($studentChoice) {
                             $questionScore += $answerWeighting;
-                            $totalScore += $answerWeighting;
+                            $answerDestination = $objAnswerTmp->selectDestination($answerId);
+                            $correctAnswerId = $answerId;
                         }
                     } else {
                         $studentChoice = $choice == $answerAutoId ? 1 : 0;
                         if ($studentChoice) {
                             $questionScore += $answerWeighting;
-                            $totalScore += $answerWeighting;
+                            $answerDestination = $objAnswerTmp->selectDestination($answerId);
+                            $correctAnswerId = $answerId;
                         }
                     }
                     break;
@@ -3741,11 +3742,11 @@ class Exercise
                     }
                     $totalScore = $questionScore;
                     break;
-                case MULTIPLE_ANSWER: //2
+                case MULTIPLE_ANSWER:
                     if ($from_database) {
                         $choice = [];
-                        $sql = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
-                                WHERE exe_id = '".$exeId."' AND question_id= '".$questionId."'";
+                        $sql = "SELECT answer FROM $TBL_TRACK_ATTEMPT
+                                WHERE exe_id = $exeId AND question_id = $questionId ";
                         $resultans = Database::query($sql);
                         while ($row = Database::fetch_array($resultans)) {
                             $choice[$row['answer']] = 1;
@@ -3775,7 +3776,7 @@ class Exercise
                     if ($from_database) {
                         $choice = [];
                         $sql = "SELECT answer FROM $TBL_TRACK_ATTEMPT
-                                WHERE exe_id = '".$exeId."' AND question_id= '".$questionId."'";
+                                WHERE exe_id = $exeId AND question_id = $questionId ";
                         $resultans = Database::query($sql);
                         while ($row = Database::fetch_array($resultans)) {
                             $choice[$row['answer']] = 1;
@@ -3800,8 +3801,8 @@ class Exercise
                 case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE:
                     if ($from_database) {
                         $choice = [];
-                        $sql = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
-                                WHERE exe_id = $exeId AND question_id= ".$questionId;
+                        $sql = "SELECT answer FROM $TBL_TRACK_ATTEMPT
+                                WHERE exe_id = $exeId AND question_id = $questionId";
                         $resultans = Database::query($sql);
                         while ($row = Database::fetch_array($resultans)) {
                             $result = explode(':', $row['answer']);
@@ -3870,11 +3871,8 @@ class Exercise
                                 FROM $TBL_TRACK_ATTEMPT
                                 WHERE
                                     exe_id = $exeId AND
-                                    question_id= ".intval($questionId);
+                                    question_id= $questionId ";
                         $result = Database::query($sql);
-                        if ($debug) {
-                            error_log($sql);
-                        }
                         $str = $answerFromDatabase = Database::result($result, 0, 'answer');
                     }
 
@@ -4176,10 +4174,10 @@ class Exercise
                             }
 
                             if ($from_database) {
-                                $sql = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
-                                    WHERE
-                                        exe_id = '".$exeId."' AND
-                                        question_id = ".intval($questionId);
+                                $sql = "SELECT answer FROM $TBL_TRACK_ATTEMPT
+                                        WHERE
+                                            exe_id = $exeId AND
+                                            question_id = $questionId ";
                                 $result = Database::query($sql);
                                 $str = Database::result($result, 0, 'answer');
                                 api_preg_match_all('#\[([^[]*)\]#', $str, $arr);
@@ -4187,14 +4185,12 @@ class Exercise
                                 $choice = $arr[1];
                                 if (isset($choice[$j])) {
                                     $tmp = api_strrpos($choice[$j], ' / ');
-
                                     if ($tmp) {
                                         $choice[$j] = api_substr($choice[$j], 0, $tmp);
                                     } else {
                                         $tmp = ltrim($tmp, '[');
                                         $tmp = rtrim($tmp, ']');
                                     }
-
                                     $choice[$j] = trim($choice[$j]);
                                     // Needed to let characters ' and " to work as part of an answer
                                     $choice[$j] = stripslashes($choice[$j]);
@@ -4242,14 +4238,12 @@ class Exercise
                                 $answer .= ''; // remove &nbsp; that causes issue
                             }
                             // adds the correct word, followed by ] to close the blank
-
                             if ($this->results_disabled != EXERCISE_FEEDBACK_TYPE_EXAM) {
                                 $answer .= ' / <font color="green"><b>'.$realCorrectTags[$i].'</b></font>';
                                 $calculatedStatus = Display::label(get_lang('Correct'), 'success');
                                 $expectedAnswer = $realCorrectTags[$i];
                             }
                             $answer .= ']';
-
                             if (isset($realText[$i + 1])) {
                                 $answer .= $realText[$i + 1];
                             }
@@ -4257,10 +4251,10 @@ class Exercise
                     } else {
                         if ($from_database) {
                             $sql = "SELECT *
-                                FROM $TBL_TRACK_ATTEMPT
-                                WHERE
-                                    exe_id = $exeId AND
-                                    question_id = $questionId";
+                                    FROM $TBL_TRACK_ATTEMPT
+                                    WHERE
+                                        exe_id = $exeId AND
+                                        question_id = $questionId ";
                             $result = Database::query($sql);
                             $resultData = Database::fetch_array($result, 'ASSOC');
                             $answer = $resultData['answer'];
@@ -4629,7 +4623,7 @@ class Exercise
                                             WHERE
                                                 hotspot_exe_id = $exeId AND
                                                 hotspot_question_id= $questionId AND
-                                                hotspot_answer_id = ".intval($answerIid)."
+                                                hotspot_answer_id = $answerIid
                                             ORDER BY hotspot_id ASC";
                                     $result = Database::query($sql);
 
@@ -4707,10 +4701,10 @@ class Exercise
                         $query = "SELECT hotspot_correct, hotspot_coordinate
                                     FROM $TBL_TRACK_HOTSPOT
                                     WHERE
-                                        hotspot_exe_id = '".$exeId."' AND
-                                        hotspot_question_id= '".$questionId."' AND
-                                        hotspot_answer_id='1'";
-                        //by default we take 1 because it's a delineation
+                                        hotspot_exe_id = $exeId AND
+                                        hotspot_question_id= $questionId AND
+                                        hotspot_answer_id = '1'";
+                        // By default we take 1 because it's a delineation
                         $resq = Database::query($query);
                         $row = Database::fetch_array($resq, 'ASSOC');
 
@@ -4734,45 +4728,38 @@ class Exercise
                         if ($answerId === 1) {
                             $studentChoice = $choice[$answerId];
                             $questionScore += $answerWeighting;
-
-                            if ($hotspot_delineation_result[1] == 1) {
-                                $totalScore += $answerWeighting; //adding the total
-                            }
+                        }
+                        if (isset($_SESSION['exerciseResultCoordinates'][$questionId])) {
+                            $user_array = $_SESSION['exerciseResultCoordinates'][$questionId];
                         }
                     }
-                    $_SESSION['hotspot_coord'][1] = $delineation_cord;
-                    $_SESSION['hotspot_dest'][1] = $answer_delineation_destination;
+                    $_SESSION['hotspot_coord'][$questionId][1] = $delineation_cord;
+                    $_SESSION['hotspot_dest'][$questionId][1] = $answer_delineation_destination;
                     break;
                 case ANNOTATION:
                     if ($from_database) {
-                        $sql = "SELECT answer, marks FROM $TBL_TRACK_ATTEMPT
+                        $sql = "SELECT answer, marks 
+                                FROM $TBL_TRACK_ATTEMPT
                                 WHERE 
                                   exe_id = $exeId AND 
-                                  question_id= ".$questionId;
+                                  question_id = $questionId ";
                         $resq = Database::query($sql);
                         $data = Database::fetch_array($resq);
 
                         $questionScore = empty($data['marks']) ? 0 : $data['marks'];
-                        $totalScore += $questionScore == -1 ? 0 : $questionScore;
-
                         $arrques = $questionName;
                         break;
                     }
                     $studentChoice = $choice;
                     if ($studentChoice) {
                         $questionScore = 0;
-                        $totalScore += 0;
                     }
                     break;
-            } // end switch Answertype
+            }
 
             if ($show_result) {
-                if ($debug) {
-                    error_log('Showing questions $from '.$from);
-                }
-
                 if ($from === 'exercise_result') {
-                    //display answers (if not matching type, or if the answer is correct)
+                    // Display answers (if not matching type, or if the answer is correct)
                     if (!in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE]) ||
                         $answerCorrect
                     ) {
@@ -4892,11 +4879,8 @@ class Exercise
                             );
                         } elseif ($answerType == HOT_SPOT) {
                             $correctAnswerId = 0;
-                            /**
-                             * @var int
-                             * @var TrackEHotspot $hotspot
-                             */
-                            foreach ($orderedHotspots as $correctAnswerId => $hotspot) {
+                            /** @var TrackEHotspot $hotspot */
+                            foreach ($orderedHotSpots as $correctAnswerId => $hotspot) {
                                 if ($hotspot->getHotspotAnswerId() == $answerAutoId) {
                                     break;
                                 }
@@ -4925,7 +4909,7 @@ class Exercise
                         } elseif ($answerType == HOT_SPOT_DELINEATION) {
                             $user_answer = $_SESSION['exerciseResultCoordinates'][$questionId];
 
-                            //round-up the coordinates
+                            // Round-up the coordinates
                             $coords = explode('/', $user_answer);
                             $user_array = '';
                             foreach ($coords as $coord) {
@@ -4937,14 +4921,13 @@ class Exercise
                                 }
                             }
                             $user_array = substr($user_array, 0, -1);
-
                             if ($next) {
                                 $user_answer = $user_array;
-                                // we compare only the delineation not the other points
-                                $answer_question = $_SESSION['hotspot_coord'][1];
-                                $answerDestination = $_SESSION['hotspot_dest'][1];
+                                // We compare only the delineation not the other points
+                                $answer_question = $_SESSION['hotspot_coord'][$questionId][1];
+                                $answerDestination = $_SESSION['hotspot_dest'][$questionId][1];
 
-                                //calculating the area
+                                // Calculating the area
                                 $poly_user = convert_coordinates($user_answer, '/');
                                 $poly_answer = convert_coordinates($answer_question, '|');
                                 $max_coord = poly_get_max($poly_user, $poly_answer);
@@ -4958,14 +4941,13 @@ class Exercise
                                 $missing = $poly_results['s1Only'];
                                 $excess = $poly_results['s2Only'];
 
-                                //$overlap = round(polygons_overlap($poly_answer,$poly_user));
                                 // //this is an area in pixels
                                 if ($debug > 0) {
                                     error_log(__LINE__.' - Polygons results are '.print_r($poly_results, 1), 0);
                                 }
 
                                 if ($overlap < 1) {
-                                    //shortcut to avoid complicated calculations
+                                    // Shortcut to avoid complicated calculations
                                     $final_overlap = 0;
                                     $final_missing = 100;
                                     $final_excess = 100;
@@ -4990,7 +4972,7 @@ class Exercise
                                     }
                                 }
 
-                                //checking the destination parameters parsing the "@@"
+                                // Checking the destination parameters parsing the "@@"
                                 $destination_items = explode(
                                     '@@',
                                     $answerDestination
@@ -5008,15 +4990,13 @@ class Exercise
                                 if ($answerId === 1) {
                                     //setting colors
                                     if ($final_overlap >= $threadhold1) {
-                                        $overlap_color = true; //echo 'a';
+                                        $overlap_color = true;
                                     }
-                                    //echo $excess.'-'.$threadhold2;
                                     if ($final_excess <= $threadhold2) {
-                                        $excess_color = true; //echo 'b';
+                                        $excess_color = true;
                                     }
-                                    //echo '--------'.$missing.'-'.$threadhold3;
                                     if ($final_missing <= $threadhold3) {
-                                        $missing_color = true; //echo 'c';
+                                        $missing_color = true;
                                     }
 
                                     // if pass
@@ -5308,8 +5288,8 @@ class Exercise
                             if ($next) {
                                 $user_answer = $user_array;
                                 // we compare only the delineation not the other points
-                                $answer_question = $_SESSION['hotspot_coord'][1];
-                                $answerDestination = $_SESSION['hotspot_dest'][1];
+                                $answer_question = $_SESSION['hotspot_coord'][$questionId][1];
+                                $answerDestination = $_SESSION['hotspot_dest'][$questionId][1];
 
                                 // calculating the area
                                 $poly_user = convert_coordinates($user_answer, '/');
@@ -5333,20 +5313,21 @@ class Exercise
                                     $final_missing = 100;
                                     $final_excess = 100;
                                 } else {
-                                    // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon
+                                    // the final overlap is the percentage of the initial polygon
+                                    // that is overlapped by the user's polygon
                                     $final_overlap = round(((float) $overlap / (float) $poly_answer_area) * 100);
-                                    if ($debug > 1) {
-                                        error_log(__LINE__.' - Final overlap is '.$final_overlap, 0);
-                                    }
-                                    // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon
+
+                                    // the final missing area is the percentage of the initial polygon that
+                                    // is not overlapped by the user's polygon
                                     $final_missing = 100 - $final_overlap;
-                                    if ($debug > 1) {
-                                        error_log(__LINE__.' - Final missing is '.$final_missing, 0);
-                                    }
-                                    // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon
+                                    // the final excess area is the percentage of the initial polygon's size that is
+                                    // covered by the user's polygon outside of the initial polygon
                                     $final_excess = round((((float) $poly_user_area - (float) $overlap) / (float) $poly_answer_area) * 100);
+
                                     if ($debug > 1) {
-                                        error_log(__LINE__.' - Final excess is '.$final_excess, 0);
+                                        error_log(__LINE__.' - Final overlap is '.$final_overlap);
+                                        error_log(__LINE__.' - Final excess is '.$final_excess);
+                                        error_log(__LINE__.' - Final missing is '.$final_missing);
                                     }
                                 }
 
@@ -5361,13 +5342,13 @@ class Exercise
                                 if ($answerId === 1) {
                                     //setting colors
                                     if ($final_overlap >= $threadhold1) {
-                                        $overlap_color = true; //echo 'a';
+                                        $overlap_color = true;
                                     }
                                     if ($final_excess <= $threadhold2) {
-                                        $excess_color = true; //echo 'b';
+                                        $excess_color = true;
                                     }
                                     if ($final_missing <= $threadhold3) {
-                                        $missing_color = true; //echo 'c';
+                                        $missing_color = true;
                                     }
 
                                     // if pass
@@ -5387,7 +5368,7 @@ class Exercise
                                         $destination_items = explode('@@', $answerDestination);
                                     }
                                 } elseif ($answerId > 1) {
-                                    if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') {
+                                    if ($objAnswerTmp->selectHotspotType($answerId) === 'noerror') {
                                         if ($debug > 0) {
                                             error_log(__LINE__.' - answerId is of type noerror', 0);
                                         }
@@ -5425,11 +5406,6 @@ class Exercise
                                         $url_hotspot = $destination_items[4];
                                     }
                                 }
-                            } else {
-                                // the first delineation feedback
-                                if ($debug > 0) {
-                                    error_log(__LINE__.' first', 0);
-                                }
                             }
                             break;
                         case HOT_SPOT_ORDER:
@@ -5468,9 +5444,6 @@ class Exercise
                     }
                 }
             }
-            if ($debug) {
-                error_log(' ------ ');
-            }
         } // end for that loops over all answers of the current question
 
         if ($debug) {
@@ -5493,43 +5466,9 @@ class Exercise
                 //getting only the first score where we save the weight of all the question
                 $answerWeighting = $objAnswerTmp->selectWeighting(1);
                 $questionScore += $answerWeighting;
-                $totalScore += $answerWeighting;
             }
         }
 
-        //Fixes multiple answer question in order to be exact
-        //if ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) {
-        /* if ($answerType == GLOBAL_MULTIPLE_ANSWER) {
-             $diff = @array_diff($answer_correct_array, $real_answers);
-
-             // All good answers or nothing works like exact
-
-             $counter = 1;
-             $correct_answer = true;
-             foreach ($real_answers as $my_answer) {
-                 if ($debug)
-                     error_log(" my_answer: $my_answer answer_correct_array[counter]: ".$answer_correct_array[$counter]);
-                 if ($my_answer != $answer_correct_array[$counter]) {
-                     $correct_answer = false;
-                     break;
-                 }
-                 $counter++;
-             }
-
-             if ($debug) error_log(" answer_correct_array: ".print_r($answer_correct_array, 1)."");
-             if ($debug) error_log(" real_answers: ".print_r($real_answers, 1)."");
-             if ($debug) error_log(" correct_answer: ".$correct_answer);
-
-             if ($correct_answer == false) {
-                 $questionScore = 0;
-             }
-
-             // This makes the result non exact
-             if (!empty($diff)) {
-                 $questionScore = 0;
-             }
-         }*/
-
         $extra_data = [
             'final_overlap' => $final_overlap,
             'final_missing' => $final_missing,
@@ -5542,7 +5481,7 @@ class Exercise
             'threadhold3' => $threadhold3,
         ];
 
-        if ($from == 'exercise_result') {
+        if ($from === 'exercise_result') {
             // if answer is hotspot. To the difference of exercise_show.php,
             //  we use the results from the session (from_db=0)
             // TODO Change this, because it is wrong to show the user
@@ -5551,25 +5490,22 @@ class Exercise
                 if ($debug) {
                     error_log('$from AND this is a hotspot kind of question ');
                 }
-                $my_exe_id = 0;
-                $from_database = 0;
-                if ($answerType == HOT_SPOT_DELINEATION) {
-                    if (0) {
+                if ($answerType === HOT_SPOT_DELINEATION) {
+                    if ($showHotSpotDelineationTable) {
+                        $overlap_color = 'red';
                         if ($overlap_color) {
                             $overlap_color = 'green';
-                        } else {
-                            $overlap_color = 'red';
                         }
+                        $missing_color = 'red';
                         if ($missing_color) {
                             $missing_color = 'green';
-                        } else {
-                            $missing_color = 'red';
                         }
+
+                        $excess_color = 'red';
                         if ($excess_color) {
                             $excess_color = 'green';
-                        } else {
-                            $excess_color = 'red';
                         }
+
                         if (!is_numeric($final_overlap)) {
                             $final_overlap = 0;
                         }
@@ -5610,21 +5546,18 @@ class Exercise
                                 </tr>
                             </table>';
                         if ($next == 0) {
-                            $try = $try_hotspot;
+                            /*$try = $try_hotspot;
                             $lp = $lp_hotspot;
                             $destinationid = $select_question_hotspot;
-                            $url = $url_hotspot;
+                            $url = $url_hotspot;*/
                         } else {
-                            //show if no error
-                            //echo 'no error';
                             $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers);
                             $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers);
                         }
 
-                        echo '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>
-                            <p style="text-align:center">';
-
-                        $message = '<p>'.get_lang('YourDelineation').'</p>';
+                        $message = '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>
+                                    <p style="text-align:center">';
+                        $message .= '<p>'.get_lang('YourDelineation').'</p>';
                         $message .= $table_resume;
                         $message .= '<br />'.get_lang('ResultIs').' '.$result_comment.'<br />';
                         if ($organs_at_risk_hit > 0) {
@@ -5632,22 +5565,24 @@ class Exercise
                         }
                         $message .= '<p>'.$comment.'</p>';
                         echo $message;
+
+                        $_SESSION['hotspot_delineation_result'][$this->selectId()][$questionId][0] = $message;
+                        $_SESSION['hotspot_delineation_result'][$this->selectId()][$questionId][1] = $_SESSION['exerciseResultCoordinates'][$questionId];
                     } else {
-                        echo $hotspot_delineation_result[0]; //prints message
-                        $from_database = 1; // the hotspot_solution.swf needs this variable
+                        echo $hotspot_delineation_result[0];
                     }
 
-                    //save the score attempts
+                    // Save the score attempts
                     if (1) {
                         //getting the answer 1 or 0 comes from exercise_submit_modal.php
-                        $final_answer = $hotspot_delineation_result[1];
+                        $final_answer = isset($hotspot_delineation_result[1]) ? $hotspot_delineation_result[1] : '';
                         if ($final_answer == 0) {
                             $questionScore = 0;
                         }
                         // we always insert the answer_id 1 = delineation
                         Event::saveQuestionAttempt($questionScore, 1, $quesId, $exeId, 0);
                         //in delineation mode, get the answer from $hotspot_delineation_result[1]
-                        $hotspotValue = (int) $hotspot_delineation_result[1] === 1 ? 1 : 0;
+                        $hotspotValue = isset($hotspot_delineation_result[1]) ? (int) $hotspot_delineation_result[1] === 1 ? 1 : 0 : 0;
                         Event::saveExerciseAttemptHotspot(
                             $exeId,
                             $quesId,
@@ -5687,7 +5622,6 @@ class Exercise
                             }
                         }
                     }
-                    $my_exe_id = $exeId;
                 }
             }
 
@@ -5938,9 +5872,6 @@ class Exercise
                         exe_result = exe_result + ".floatval($questionScore)."
                     WHERE exe_id = $exeId";
             Database::query($sql);
-            if ($debug) {
-                error_log($sql);
-            }
         }
 
         $return = [
@@ -5952,6 +5883,8 @@ class Exercise
             'answer_type' => $answerType,
             'generated_oral_file' => $generatedFile,
             'user_answered' => $userAnsweredQuestion,
+            'correct_answer_id' => $correctAnswerId,
+            'answer_destination' => $answerDestination,
         ];
 
         return $return;
@@ -9547,6 +9480,189 @@ class Exercise
         return 0;
     }
 
+    /**
+     * @param Question $objQuestionTmp
+     * @param int      $questionId
+     * @param bool     $show_results
+     * @param array    $question_result
+     */
+    public function getDelineationResult(Question $objQuestionTmp, $questionId, $show_results, $question_result)
+    {
+        $id = (int) $objQuestionTmp->id;
+        $questionId = (int) $questionId;
+
+        $final_overlap = $question_result['extra']['final_overlap'];
+        $final_missing = $question_result['extra']['final_missing'];
+        $final_excess = $question_result['extra']['final_excess'];
+
+        $overlap_color = $question_result['extra']['overlap_color'];
+        $missing_color = $question_result['extra']['missing_color'];
+        $excess_color = $question_result['extra']['excess_color'];
+
+        $threadhold1 = $question_result['extra']['threadhold1'];
+        $threadhold2 = $question_result['extra']['threadhold2'];
+        $threadhold3 = $question_result['extra']['threadhold3'];
+
+        if ($show_results) {
+            if ($overlap_color) {
+                $overlap_color = 'green';
+            } else {
+                $overlap_color = 'red';
+            }
+
+            if ($missing_color) {
+                $missing_color = 'green';
+            } else {
+                $missing_color = 'red';
+            }
+            if ($excess_color) {
+                $excess_color = 'green';
+            } else {
+                $excess_color = 'red';
+            }
+
+            if (!is_numeric($final_overlap)) {
+                $final_overlap = 0;
+            }
+
+            if (!is_numeric($final_missing)) {
+                $final_missing = 0;
+            }
+            if (!is_numeric($final_excess)) {
+                $final_excess = 0;
+            }
+
+            if ($final_excess > 100) {
+                $final_excess = 100;
+            }
+
+            $table_resume = '
+                    <table class="data_table">
+                        <tr class="row_odd" >
+                            <td>&nbsp;</td>
+                            <td><b>'.get_lang('Requirements').'</b></td>
+                            <td><b>'.get_lang('YourAnswer').'</b></td>
+                        </tr>
+                        <tr class="row_even">
+                            <td><b>'.get_lang('Overlap').'</b></td>
+                            <td>'.get_lang('Min').' '.$threadhold1.'</td>
+                            <td>
+                                <div style="color:'.$overlap_color.'">
+                                    '.(($final_overlap < 0) ? 0 : intval($final_overlap)).'
+                                </div>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td><b>'.get_lang('Excess').'</b></td>
+                            <td>'.get_lang('Max').' '.$threadhold2.'</td>
+                            <td>
+                                <div style="color:'.$excess_color.'">
+                                    '.(($final_excess < 0) ? 0 : intval($final_excess)).'
+                                </div>
+                            </td>
+                        </tr>
+                        <tr class="row_even">
+                            <td><b>'.get_lang('Missing').'</b></td>
+                            <td>'.get_lang('Max').' '.$threadhold3.'</td>
+                            <td>
+                                <div style="color:'.$missing_color.'">
+                                    '.(($final_missing < 0) ? 0 : intval($final_missing)).'
+                                </div>
+                            </td>
+                        </tr>
+                    </table>
+                ';
+
+            $answerType = $objQuestionTmp->selectType();
+            if ($answerType != HOT_SPOT_DELINEATION) {
+                $item_list = explode('@@', $destination);
+                $try = $item_list[0];
+                $lp = $item_list[1];
+                $destinationid = $item_list[2];
+                $url = $item_list[3];
+                $table_resume = '';
+            } else {
+                if ($next == 0) {
+                    $try = $try_hotspot;
+                    $lp = $lp_hotspot;
+                    $destinationid = $select_question_hotspot;
+                    $url = $url_hotspot;
+                } else {
+                    //show if no error
+                    $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers);
+                    $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers);
+                }
+            }
+
+            echo '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>';
+            if ($answerType == HOT_SPOT_DELINEATION) {
+                if ($organs_at_risk_hit > 0) {
+                    $message = '<br />'.get_lang('ResultIs').' <b>'.$result_comment.'</b><br />';
+                    $message .= '<p style="color:#DC0A0A;"><b>'.get_lang('OARHit').'</b></p>';
+                } else {
+                    $message = '<p>'.get_lang('YourDelineation').'</p>';
+                    $message .= $table_resume;
+                    $message .= '<br />'.get_lang('ResultIs').' <b>'.$result_comment.'</b><br />';
+                }
+                $message .= '<p>'.$comment.'</p>';
+                echo $message;
+            } else {
+                echo '<p>'.$comment.'</p>';
+            }
+
+            // Showing the score
+            /*$queryfree = "SELECT marks FROM $TBL_TRACK_ATTEMPT
+                          WHERE exe_id = $id AND question_id =  $questionId";
+            $resfree = Database::query($queryfree);
+            $questionScore = Database::result($resfree, 0, 'marks');
+            $totalScore += $questionScore;*/
+            $relPath = api_get_path(REL_PATH);
+            echo '</table></td></tr>';
+            echo "
+                        <tr>
+                            <td colspan=\"2\">
+                                <div id=\"hotspot-solution\"></div>
+                                <script>
+                                    $(function() {
+                                        new HotspotQuestion({
+                                            questionId: $questionId,
+                                            exerciseId: {$this->id},
+                                            exeId: $id,
+                                            selector: '#hotspot-solution',
+                                            for: 'solution',
+                                            relPath: '$relPath'
+                                        });
+                                    });
+                                </script>
+                            </td>
+                        </tr>
+                    </table>
+                ";
+        }
+    }
+
+    /**
+     * Clean exercise session variables.
+     */
+    public static function cleanSessionVariables()
+    {
+        Session::erase('objExercise');
+        Session::erase('exe_id');
+        Session::erase('calculatedAnswerId');
+        Session::erase('duration_time_previous');
+        Session::erase('duration_time');
+        Session::erase('objQuestion');
+        Session::erase('objAnswer');
+        Session::erase('questionList');
+        Session::erase('exerciseResult');
+        Session::erase('firstTime');
+
+        Session::erase('exerciseResultCoordinates');
+        Session::erase('hotspot_coord');
+        Session::erase('hotspot_dest');
+        Session::erase('hotspot_delineation_result');
+    }
+
     /**
      * Gets the question list ordered by the question_order setting (drag and drop).
      *

+ 1 - 9
main/exercise/exercise.php

@@ -69,15 +69,7 @@ $exercisePath = substr($exercisePath, 0, strpos($exercisePath, $exfile));
 $exercisePath = $exercisePath.'exercise.php';
 
 // Clear the exercise session
-Session::erase('objExercise');
-Session::erase('objQuestion');
-Session::erase('objAnswer');
-Session::erase('questionList');
-Session::erase('exerciseResult');
-Session::erase('firstTime');
-Session::erase('calculatedAnswerId');
-Session::erase('duration_time_previous');
-Session::erase('duration_time');
+Exercise::cleanSessionVariables();
 
 //General POST/GET/SESSION/COOKIES parameters recovery
 $origin = api_get_origin();

+ 13 - 34
main/exercise/exercise_result.php

@@ -36,9 +36,6 @@ $origin = api_get_origin();
 if (empty($objExercise)) {
     $objExercise = Session::read('objExercise');
 }
-if (empty($remind_list)) {
-    $remind_list = isset($_REQUEST['remind_list']) ? $_REQUEST['remind_list'] : null;
-}
 
 $exe_id = isset($_REQUEST['exe_id']) ? (int) $_REQUEST['exe_id'] : 0;
 
@@ -106,19 +103,12 @@ if (api_is_course_admin() && !in_array($origin, ['learnpath', 'embeddable'])) {
         Display::return_icon('edit.png', get_lang('ModifyExercise'), [], 32).'</a>';
     echo '</div>';
 }
-
-$feedback_type = $objExercise->getFeedbackType();
 $exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id);
-
-if (!empty($exercise_stat_info['data_tracking'])) {
-    $question_list = explode(',', $exercise_stat_info['data_tracking']);
-}
-
 $learnpath_id = isset($exercise_stat_info['orig_lp_id']) ? $exercise_stat_info['orig_lp_id'] : 0;
 $learnpath_item_id = isset($exercise_stat_info['orig_lp_item_id']) ? $exercise_stat_info['orig_lp_item_id'] : 0;
 $learnpath_item_view_id = isset($exercise_stat_info['orig_lp_item_view_id']) ? $exercise_stat_info['orig_lp_item_view_id'] : 0;
 
-if ($origin == 'learnpath') {
+if ($origin === 'learnpath') {
     ?>
     <form method="GET" action="exercise.php?<?php echo api_get_cidreq(); ?>">
     <input type="hidden" name="origin" value="<?php echo $origin; ?>" />
@@ -129,7 +119,6 @@ if ($origin == 'learnpath') {
 }
 
 $i = $total_score = $max_score = 0;
-
 $remainingMessage = '';
 $attemptButton = '';
 
@@ -170,10 +159,9 @@ if ($objExercise->selectAttempts() > 0) {
     } else {
         $attempt_count++;
         $remainingAttempts = $objExercise->selectAttempts() - $attempt_count;
-
         if ($remainingAttempts) {
             $attemptMessage = sprintf(get_lang('RemainingXAttempts'), $remainingAttempts);
-            $remainingMessage = sprintf("<p>%s</p> %s", $attemptMessage, $attemptButton);
+            $remainingMessage = sprintf('<p>%s</p> %s', $attemptMessage, $attemptButton);
         }
     }
 } else {
@@ -187,19 +175,23 @@ if (!empty($exercise_stat_info)) {
 
 $max_score = $objExercise->get_max_score();
 
-if ($origin !== 'embeddable') {
+if ($origin === 'embeddable') {
+    showEmbeddableFinishButton();
+} else {
     echo Display::return_message(get_lang('Saved').'<br />', 'normal', false);
 }
 
-if ($origin == 'embeddable') {
-    showEmbeddableFinishButton();
+$saveResults = true;
+$feedbackType = $objExercise->getFeedbackType();
+if (!in_array($feedbackType, [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP])) {
+    //$saveResults = false;
 }
 
 // Display and save questions
 ExerciseLib::displayQuestionListByAttempt(
     $objExercise,
     $exe_id,
-    true,
+    $saveResults,
     $remainingMessage
 );
 
@@ -222,20 +214,12 @@ if (!in_array($origin, ['learnpath', 'embeddable'])) {
     echo '</div>';
 
     if (api_is_allowed_to_session_edit()) {
-        Session::erase('objExercise');
-        Session::erase('exe_id');
-        Session::erase('calculatedAnswerId');
-        Session::erase('duration_time_previous');
-        Session::erase('duration_time');
+        Exercise::cleanSessionVariables();
     }
     Display::display_footer();
 } elseif ($origin === 'embeddable') {
     if (api_is_allowed_to_session_edit()) {
-        Session::erase('objExercise');
-        Session::erase('exe_id');
-        Session::erase('calculatedAnswerId');
-        Session::erase('duration_time_previous');
-        Session::erase('duration_time');
+        Exercise::cleanSessionVariables();
     }
 
     Session::write('attempt_remaining', $remainingMessage);
@@ -247,18 +231,13 @@ if (!in_array($origin, ['learnpath', 'embeddable'])) {
     $href = $lp_mode === 'fullscreen' ? ' window.opener.location.href="'.$url.'" ' : ' top.location.href="'.$url.'"';
 
     if (api_is_allowed_to_session_edit()) {
-        Session::erase('objExercise');
-        Session::erase('exe_id');
-        Session::erase('calculatedAnswerId');
-        Session::erase('duration_time_previous');
-        Session::erase('duration_time');
+        Exercise::cleanSessionVariables();
     }
     Session::write('attempt_remaining', $remainingMessage);
 
     // Record the results in the learning path, using the SCORM interface (API)
     echo "<script>window.parent.API.void_save_asset('$total_score', '$max_score', 0, 'completed');</script>";
     echo '<script type="text/javascript">'.$href.'</script>';
-
     Display::display_reduced_footer();
 }
 

+ 3 - 147
main/exercise/exercise_show.php

@@ -524,152 +524,8 @@ foreach ($questionList as $questionId) {
             $questionScore = $question_result['score'];
             $totalScore += $question_result['score'];
 
-            $final_overlap = $question_result['extra']['final_overlap'];
-            $final_missing = $question_result['extra']['final_missing'];
-            $final_excess = $question_result['extra']['final_excess'];
-
-            $overlap_color = $question_result['extra']['overlap_color'];
-            $missing_color = $question_result['extra']['missing_color'];
-            $excess_color = $question_result['extra']['excess_color'];
-
-            $threadhold1 = $question_result['extra']['threadhold1'];
-            $threadhold2 = $question_result['extra']['threadhold2'];
-            $threadhold3 = $question_result['extra']['threadhold3'];
-
-            if ($show_results) {
-                if ($overlap_color) {
-                    $overlap_color = 'green';
-                } else {
-                    $overlap_color = 'red';
-                }
-
-                $missing_color = 'red';
-                if ($missing_color) {
-                    $missing_color = 'green';
-                }
-                $excess_color = 'red';
-                if ($excess_color) {
-                    $excess_color = 'green';
-                }
-
-                if (!is_numeric($final_overlap)) {
-                    $final_overlap = 0;
-                }
-
-                if (!is_numeric($final_missing)) {
-                    $final_missing = 0;
-                }
-                if (!is_numeric($final_excess)) {
-                    $final_excess = 0;
-                }
-
-                if ($final_excess > 100) {
-                    $final_excess = 100;
-                }
-
-                $table_resume = '
-                    <table class="data_table">
-                        <tr class="row_odd" >
-                            <td>&nbsp;</td>
-                            <td><b>'.get_lang('Requirements').'</b></td>
-                            <td><b>'.get_lang('YourAnswer').'</b></td>
-                        </tr>
-                        <tr class="row_even">
-                            <td><b>'.get_lang('Overlap').'</b></td>
-                            <td>'.get_lang('Min').' '.$threadhold1.'</td>
-                            <td>
-                                <div style="color:'.$overlap_color.'">
-                                    '.(($final_overlap < 0) ? 0 : intval($final_overlap)).'
-                                </div>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td><b>'.get_lang('Excess').'</b></td>
-                            <td>'.get_lang('Max').' '.$threadhold2.'</td>
-                            <td>
-                                <div style="color:'.$excess_color.'">
-                                    '.(($final_excess < 0) ? 0 : intval($final_excess)).'
-                                </div>
-                            </td>
-                        </tr>
-                        <tr class="row_even">
-                            <td><b>'.get_lang('Missing').'</b></td>
-                            <td>'.get_lang('Max').' '.$threadhold3.'</td>
-                            <td>
-                                <div style="color:'.$missing_color.'">
-                                    '.(($final_missing < 0) ? 0 : intval($final_missing)).'
-                                </div>
-                            </td>
-                        </tr>
-                    </table>
-                ';
-
-                if ($answerType != HOT_SPOT_DELINEATION) {
-                    $item_list = explode('@@', $destination);
-
-                    $try = $item_list[0];
-                    $lp = $item_list[1];
-                    $destinationid = $item_list[2];
-                    $url = $item_list[3];
-                    $table_resume = '';
-                } else {
-                    if ($next == 0) {
-                        $try = $try_hotspot;
-                        $lp = $lp_hotspot;
-                        $destinationid = $select_question_hotspot;
-                        $url = $url_hotspot;
-                    } else {
-                        //show if no error
-                        $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers);
-                        $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers);
-                    }
-                }
-
-                echo '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>';
-                if ($answerType == HOT_SPOT_DELINEATION) {
-                    if ($organs_at_risk_hit > 0) {
-                        $message = '<br />'.get_lang('ResultIs').' <b>'.$result_comment.'</b><br />';
-                        $message .= '<p style="color:#DC0A0A;"><b>'.get_lang('OARHit').'</b></p>';
-                    } else {
-                        $message = '<p>'.get_lang('YourDelineation').'</p>';
-                        $message .= $table_resume;
-                        $message .= '<br />'.get_lang('ResultIs').' <b>'.$result_comment.'</b><br />';
-                    }
-                    $message .= '<p>'.$comment.'</p>';
-                    echo $message;
-                } else {
-                    echo '<p>'.$comment.'</p>';
-                }
-
-                // Showing the score
-                $queryfree = "SELECT marks FROM $TBL_TRACK_ATTEMPT 
-                              WHERE exe_id = $id AND question_id= ".intval($questionId);
-                $resfree = Database::query($queryfree);
-                $questionScore = Database::result($resfree, 0, "marks");
-                $totalScore += $questionScore;
-                $relPath = api_get_path(REL_PATH);
-                echo '</table></td></tr>';
-                echo "
-                        <tr>
-                            <td colspan=\"2\">
-                                <div id=\"hotspot-solution\"></div>
-                                <script>
-                                    $(function() {
-                                        new HotspotQuestion({
-                                            questionId: $questionId,
-                                            exerciseId: {$objExercise->id},
-                                            exeId: $id,
-                                            selector: '#hotspot-solution',
-                                            for: 'solution',
-                                            relPath: '$relPath'
-                                        });
-                                    });
-                                </script>
-                            </td>
-                        </tr>
-                    </table>
-                ";
-            }
+            //$organs_at_risk_hit
+            echo $objExercise->getDelineationResult($objQuestionTmp, $questionId, $show_results, $question_result);
             break;
         case ANNOTATION:
             $question_result = $objExercise->manage_answer(
@@ -977,7 +833,7 @@ if ($answerType != MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
 
 // Total score
 $myTotalScoreTemp = $totalScore;
-if ($origin != 'learnpath' || ($origin === 'learnpath' && isset($_GET['fb_type']))) {
+if ($origin != 'learnpath' || ($origin == 'learnpath' && isset($_GET['fb_type']))) {
     if ($show_results || $show_only_total_score || $showTotalScoreAndUserChoicesInLastAttempt) {
         $totalScoreText .= '<div class="question_row">';
         if ($objExercise->selectPropagateNeg() == 0 && $myTotalScoreTemp < 0) {

+ 8 - 13
main/exercise/exercise_submit.php

@@ -98,8 +98,6 @@ $choice = empty($choice) ? isset($_REQUEST['choice2']) ? $_REQUEST['choice2'] :
 // From submit modal
 $current_question = isset($_REQUEST['num']) ? (int) $_REQUEST['num'] : null;
 $currentAnswer = isset($_REQUEST['num_answer']) ? (int) $_REQUEST['num_answer'] : null;
-$endExercise = isset($_REQUEST['end_exercise']) && $_REQUEST['end_exercise'] == 1 ? true : false;
-
 $logInfo = [
     'tool' => TOOL_QUIZ,
     'tool_id' => $exerciseId,
@@ -1213,8 +1211,7 @@ if (!empty($error)) {
                 url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'&reminder=2";
             } else {
                 url = "exercise_submit.php?'.$params.'&num='.$current_question.'&remind_question_id='.$remind_question_id.'";
-            }
-            //$("#save_for_now_"+question_id).html(\''.Display::return_icon('save.png', get_lang('Saved'), [], ICON_SIZE_SMALL).'\');
+            }            
             window.location = url;
         }
         
@@ -1224,19 +1221,19 @@ if (!empty($error)) {
         }
 
         function save_now(question_id, url_extra, validate) {
-            //1. Normal choice inputs
+            // 1. Normal choice inputs
             var my_choice = $(\'*[name*="choice[\'+question_id+\']"]\').serialize();
-
-            //2. Reminder checkbox
+            
+            // 2. Reminder checkbox
             var remind_list = $(\'*[name*="remind_list"]\').serialize();
 
-            //3. Hotspots
+            // 3. Hotspots
             var hotspot = $(\'*[name*="hotspot[\'+question_id+\']"]\').serialize();
             
-            //4. choice for degree of certainty
+            // 4. choice for degree of certainty
             var my_choiceDc = $(\'*[name*="choiceDegreeCertainty[\'+question_id+\']"]\').serialize();
 
-            // Checking FCK
+            // Checking CkEditor
             if (question_id) {
                 if (CKEDITOR.instances["choice["+question_id+"]"]) {
                     var ckContent = CKEDITOR.instances["choice["+question_id+"]"].getData();
@@ -1313,7 +1310,7 @@ if (!empty($error)) {
             var question_list = ['.implode(',', $questionList).'];
             var free_answers = {};
             $.each(question_list, function(index, my_question_id) {
-                // Checking FCK
+                // Checking Ckeditor
                 if (my_question_id) {
                     if (CKEDITOR.instances["choice["+my_question_id+"]"]) {
                         var ckContent = CKEDITOR.instances["choice["+my_question_id+"]"].getData();
@@ -1551,10 +1548,8 @@ if (!empty($error)) {
     }
     echo '</form>';
 }
-
 if (!in_array($origin, ['learnpath', 'embeddable'])) {
     // So we are not in learnpath tool
     echo '</div>'; //End glossary div
 }
-
 Display::display_footer();

+ 149 - 431
main/exercise/exercise_submit_modal.php

@@ -14,31 +14,6 @@ api_protect_course_script();
 
 require_once api_get_path(LIBRARY_PATH).'geometry.lib.php';
 
-$message = null;
-$dbg_local = 0;
-$gradebook = null;
-$final_overlap = null;
-$final_missing = null;
-$final_excess = null;
-$threadhold1 = null;
-$threadhold2 = null;
-$threadhold3 = null;
-
-$exerciseResult = Session::read('exerciseResult');
-$exerciseResultCoordinates = isset($_REQUEST['exerciseResultCoordinates']) ? $_REQUEST['exerciseResultCoordinates'] : null;
-$origin = api_get_origin();
-
-// if origin is learnpath
-$learnpath_id = 0;
-if (isset($_REQUEST['learnpath_id'])) {
-    $learnpath_id = (int) $_REQUEST['learnpath_id'];
-}
-
-$learnpath_item_id = 0;
-if (isset($_REQUEST['learnpath_item_id'])) {
-    $learnpath_item_id = (int) $_REQUEST['learnpath_item_id'];
-}
-
 /** @var Exercise $objExercise */
 $objExercise = Session::read('objExercise');
 
@@ -46,85 +21,90 @@ if (empty($objExercise)) {
     api_not_allowed();
 }
 
-$_SESSION['hotspot_coord'] = [];
-$newQuestionList = Session::read('newquestionList', []);
+$feedbackType = $objExercise->getFeedbackType();
+$exerciseType = $objExercise->type;
+if (!in_array($feedbackType, [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP])) {
+    api_not_allowed();
+}
+
+$exerciseResult = Session::read('exerciseResult');
+$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : 0;
+$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : 0;
 $questionList = Session::read('questionList');
+
 $exerciseId = (int) $_GET['exerciseId'];
-$exerciseType = (int) $_GET['exerciseType'];
+//$exerciseType = (int) $_GET['exerciseType'];
 $questionNum = (int) $_GET['num'];
-$nbrQuestions = isset($_GET['nbrQuestions']) ? (int) $_GET['nbrQuestions'] : null;
-
-// Clean extra session variables
-Session::erase('objExerciseExtra'.$exerciseId);
-Session::erase('exerciseResultExtra'.$exerciseId);
-Session::erase('questionListExtra'.$exerciseId);
-
-// Round-up the coordinates
-$user_array = '';
-if (isset($_GET['hotspot'])) {
-    $coords = explode('/', $_GET['hotspot']);
-    if (is_array($coords) && count($coords) > 0) {
-        foreach ($coords as $coord) {
-            if (!empty($coord)) {
-                list($x, $y) = explode(';', $coord);
-                $user_array .= round($x).';'.round($y).'/';
-            }
-        }
+//$nbrQuestions = isset($_GET['nbrQuestions']) ? (int) $_GET['nbrQuestions'] : null;
+$questionId = $questionList[$questionNum];
+
+$choiceValue = isset($_GET['choice']) ? $_GET['choice'] : '';
+$hotSpot = isset($_GET['hotspot']) ? $_GET['hotspot'] : '';
+
+if (!empty($hotSpot)) {
+    if (isset($hotSpot[$questionId])) {
+        $hotSpot = $hotSpot[$questionId];
     }
 }
 
-$user_array = substr($user_array, 0, -1);
-$choice_value = '';
-if (isset($_GET['choice'])) {
-    $choice_value = (int) $_GET['choice'];
+if (!empty($choiceValue)) {
+    if (isset($choiceValue[$questionId])) {
+        $choiceValue = $choiceValue[$questionId];
+    }
 }
 
 echo '<div id="delineation-container">';
 // Getting the options by js
-if (empty($choice_value)) {
+if (empty($choiceValue) && empty($hotSpot)) {
     echo "<script>
         // this works for only radio buttons
-        var f = window.document.frm_exercise;
-        var choice_js='';
+        var f = window.document.frm_exercise;        
+        var choice_js = {answers: []};
         var hotspot = new Array();
         var hotspotcoord = new Array();
-        var counter=0;
-        for ( var i = 0; i < f.elements.length; i++ ) {
-            if (f.elements[i].type=='radio' && f.elements[i].checked) {
-                choice_js = f.elements[i].value;
+        var counter = 0;
+        
+        for (var i = 0; i < f.elements.length; i++) {            
+            if (f.elements[i].type == 'radio' && f.elements[i].checked) {                
+                choice_js.answers.push(f.elements[i].value);
+                counter ++;
+            }
+            
+            if (f.elements[i].type == 'checkbox' && f.elements[i].checked) {
+                choice_js.answers.push(f.elements[i].value);
                 counter ++;
             }
 
-            if (f.elements[i].type=='hidden' ) {
+            if (f.elements[i].type == 'hidden') {
                 var name = f.elements[i].name;
-                if (name.substr(0,7)=='hotspot')
+                
+                if (name.substr(0,7) == 'hotspot') {
                     hotspot.push(f.elements[i].value);
+                }
 
-                if (name.substr(0,20)=='hotspot_coordinates')
+                if (name.substr(0,20) == 'hotspot_coordinates') {
                     hotspotcoord.push(f.elements[i].value);
+                }
             }
         }
-
-        if (counter==0) {
-            choice_js=-1; // this is an error
-        }
-
+        
+        var my_choice = $('*[name*=\"choice[".$questionId."]\"]').serialize();
+        var hotspot = $('*[name*=\"hotspot[".$questionId."]\"]').serialize();
+        //var my_choiceDc = $('*[name*=\"choiceDegreeCertainty['+question_id+']\"]').serialize();        
     ";
+
     // IMPORTANT
-    //this is the real redirect function
-    //echo 'window.location.href = "exercise_submit_modal.php?learnpath_id='.$learnpath_id.'&learnpath_item_id='.$learnpath_item_id.'&hotspotcoord="+ hotspotcoord + "&hotspot="+ hotspot + "&choice="+ choice_js + "&exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&origin='.$origin.'&gradebook='.$gradebook.'";';
-    echo ' url = "exercise_submit_modal.php?learnpath_id='.$learnpath_id.'&learnpath_item_id='.$learnpath_item_id.'&hotspotcoord="+ hotspotcoord + "&hotspot="+ hotspot + "&choice="+ choice_js + "&exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'&gradebook='.$gradebook.'";';
+    // This is the real redirect function
+    $extraUrl = '&exerciseId='.$exerciseId.'&num='.$questionNum.'&learnpath_id='.$learnpath_id.'&learnpath_item_id='.$learnpath_item_id;
+    $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit_modal.php?'.api_get_cidreq().$extraUrl;
+    echo ' url = "'.addslashes($url).'&hotspotcoord="+ hotspotcoord + "&"+ hotspot + "&"+ my_choice;';
     echo "$('#global-modal .modal-body').load(url);";
     echo '</script>';
     exit;
 }
-
 $choice = [];
-$questionId = $questionList[$questionNum];
-// $choice_value => value of the user selection
-$choice[$questionId] = isset($choice_value) ? $choice_value : null;
+$choice[$questionId] = isset($choiceValue) ? $choiceValue : null;
 
-// initializing
 if (!is_array($exerciseResult)) {
     $exerciseResult = [];
 }
@@ -148,309 +128,103 @@ if (is_array($choice)) {
 
 // the script "exercise_result.php" will take the variable $exerciseResult from the session
 Session::write('exerciseResult', $exerciseResult);
-Session::write('exerciseResultCoordinates', $exerciseResultCoordinates);
-
-// creates a temporary Question object
-if (in_array($questionId, $questionList)) {
-    $objQuestionTmp = Question:: read($questionId);
-    $questionName = $objQuestionTmp->selectTitle();
-    $questionDescription = $objQuestionTmp->selectDescription();
-    $questionWeighting = $objQuestionTmp->selectWeighting();
-    $answerType = $objQuestionTmp->selectType();
-    $quesId = $objQuestionTmp->selectId(); //added by priya saini
-}
 
+$objQuestionTmp = Question::read($questionId);
+$answerType = $objQuestionTmp->selectType();
 $objAnswerTmp = new Answer($questionId);
 $nbrAnswers = $objAnswerTmp->selectNbrAnswers();
-$choice = $exerciseResult[$questionId];
-$destination = [];
-$comment = '';
-$next = 1;
-$_SESSION['hotspot_coord'] = [];
-$_SESSION['hotspot_dest'] = [];
-$overlap_color = $missing_color = $excess_color = false;
-$organs_at_risk_hit = 0;
-$wrong_results = false;
-$hot_spot_load = false;
-$questionScore = 0;
-$totalScore = 0;
-
-if (!empty($choice_value)) {
-    for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
-        $answer = $objAnswerTmp->selectAnswer($answerId);
-        $answerComment = $objAnswerTmp->selectComment($answerId);
-        $answerDestination = $objAnswerTmp->selectDestination($answerId);
-
-        $answerCorrect = $objAnswerTmp->isCorrect($answerId);
-        $answerWeighting = $objAnswerTmp->selectWeighting($answerId);
-        $numAnswer = $objAnswerTmp->selectAutoId($answerId);
-
-        // Delineation
-        $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1);
-        $answer_delineation_destination = $objAnswerTmp->selectDestination(1);
-
-        switch ($answerType) {
-            // for unique answer
-            case UNIQUE_ANSWER:
-                $studentChoice = $choice_value == $numAnswer ? 1 : 0;
-                if ($studentChoice) {
-                    $questionScore += $answerWeighting;
-                    $totalScore += $answerWeighting;
-                    $newQuestionList[] = $questionId;
-                }
-                break;
-            case HOT_SPOT_DELINEATION:
-                $studentChoice = $choice[$answerId];
-                if ($studentChoice) {
-                    $newQuestionList[] = $questionId;
-                }
-                if ($answerId === 1) {
-                    $questionScore += $answerWeighting;
-                    $totalScore += $answerWeighting;
-                    $_SESSION['hotspot_coord'][1] = $delineation_cord;
-                    $_SESSION['hotspot_dest'][1] = $answer_delineation_destination;
-                }
-                break;
-        }
-
-        if ($answerType == UNIQUE_ANSWER || $answerType == MULTIPLE_ANSWER) {
-            if ($studentChoice) {
-                $destination = $answerDestination;
-                $comment = $answerComment;
-            }
-        } elseif ($answerType == HOT_SPOT_DELINEATION) {
-            if ($next) {
-                $hot_spot_load = true; //apparently the script is called twice
-                $user_answer = $user_array;
-                $_SESSION['exerciseResultCoordinates'][$questionId] = $user_answer; //needed for exercise_result.php
-
-                // we compare only the delineation not the other points
-                $answer_question = $_SESSION['hotspot_coord'][1];
-                $answerDestination = $_SESSION['hotspot_dest'][1];
-
-                $poly_user = convert_coordinates($user_answer, '/');
-                $poly_answer = convert_coordinates($answer_question, '|');
-                $max_coord = poly_get_max($poly_user, $poly_answer);
-
-                if (empty($_GET['hotspot'])) { //no user response
-                    $overlap = -2;
-                } else {
-                    $poly_user_compiled = poly_compile($poly_user, $max_coord);
-                    $poly_answer_compiled = poly_compile(
-                        $poly_answer,
-                        $max_coord
-                    );
-                    $poly_results = poly_result(
-                        $poly_answer_compiled,
-                        $poly_user_compiled,
-                        $max_coord
-                    );
-
-                    $overlap = $poly_results['both'];
-                    $poly_answer_area = $poly_results['s1'];
-                    $poly_user_area = $poly_results['s2'];
-                    $missing = $poly_results['s1Only'];
-                    $excess = $poly_results['s2Only'];
-                }
+$showResult = false;
 
-                if ($overlap < 1) {
-                    // shortcut to avoid complicated calculations
-                    $final_overlap = 0;
-                    $final_missing = 100;
-                    $final_excess = 100;
-                } else {
-                    // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon
-                    $final_overlap = round(((float) $overlap / (float) $poly_answer_area) * 100);
-                    if ($dbg_local > 1) {
-                        error_log(__LINE__.' - Final overlap is '.$final_overlap, 0);
-                    }
-                    // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon
-                    $final_missing = 100 - $final_overlap;
-                    if ($dbg_local > 1) {
-                        error_log(__LINE__.' - Final missing is '.$final_missing, 0);
-                    }
-                    // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon
-                    $final_excess = round((((float) $poly_user_area - (float) $overlap) / (float) $poly_answer_area) * 100);
-                    if ($dbg_local > 1) {
-                        error_log(__LINE__.' - Final excess is '.$final_excess, 0);
-                    }
-                }
+$objAnswerTmp = new Answer($questionId, api_get_course_int_id());
+if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_DIRECT) {
+    $showResult = true;
+}
 
-                $destination_items = explode('@@', $answerDestination);
-                $threadhold_total = $destination_items[0];
-                $threadhold_items = explode(';', $threadhold_total);
-                $threadhold1 = $threadhold_items[0]; // overlap
-                $threadhold2 = $threadhold_items[1]; // excess
-                $threadhold3 = $threadhold_items[2]; //missing
-
-                // if is delineation
-                if ($answerId === 1) {
-                    //setting colors
-                    if ($final_overlap >= $threadhold1) {
-                        $overlap_color = true;
-                    }
-
-                    if ($final_excess <= $threadhold2) {
-                        $excess_color = true;
-                    }
-
-                    if ($final_missing <= $threadhold3) {
-                        $missing_color = true;
-                    }
-
-                    $try_hotspot = null;
-                    $lp_hotspot = null;
-                    $url_hotspot = null;
-                    $select_question_hotspot = null;
-
-                    // if pass
-                    //if ($final_overlap>=$threadhold1 && $final_missing<=$threadhold2 && $final_excess<=$threadhold3) {
-                    if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) {
-                        $next = 1; //go to the oars
-                        $result_comment = get_lang('Acceptable');
-                    } else {
-                        $next = 1; //Go to the oars. If $next =  0 we will show this message: "One (or more) area at risk has been hit" instead of the table resume with the results
-                        $wrong_results = true;
-                        $result_comment = get_lang('Unacceptable');
-                    }
-
-                    $special_comment = $comment = $answerDestination = $objAnswerTmp->selectComment(1);
-                    $answerDestination = $objAnswerTmp->selectDestination(1);
-                    $destination_items = explode('@@', $answerDestination);
-                    $try_hotspot = $destination_items[1];
-                    $lp_hotspot = $destination_items[2];
-                    $select_question_hotspot = $destination_items[3];
-                    $url_hotspot = $destination_items[4];
-                } elseif ($answerId > 1) {
-                    if ($objAnswerTmp->selectHotspotType($answerId) === 'noerror') {
-                        // Type no error shouldn't be treated
-                        $next = 1;
-                        continue;
-                    }
-                    //check the intersection between the oar and the user
-                    //echo 'user';	print_r($x_user_list);		print_r($y_user_list);
-                    //echo 'official';print_r($x_list);print_r($y_list);
-                    //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list);
-
-                    //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId);
-                    $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); //getting the oars coordinates
-                    $poly_answer = convert_coordinates($delineation_cord, '|');
-                    // getting max coordinates
-                    $max_coord = poly_get_max(
-                        $poly_user,
-                        $poly_answer
-                    );
-                    $test = false;
-                    if (empty($_GET['hotspot'])) {
-                        // no user response
-                        $overlap = false;
-                    } else {
-                        // poly_compile really works tested with gnuplot
-                        $poly_user_compiled = poly_compile(
-                            $poly_user,
-                            $max_coord,
-                            $test
-                        ); //$poly_user is already set when answerid = 1
-                        $poly_answer_compiled = poly_compile(
-                            $poly_answer,
-                            $max_coord,
-                            $test
-                        );
-                        $overlap = poly_touch(
-                            $poly_user_compiled,
-                            $poly_answer_compiled,
-                            $max_coord
-                        );
-                    }
-
-                    if ($overlap == false) {
-                        //all good, no overlap
-                        $next = 1;
-                        continue;
-                    } else {
-                        if ($dbg_local > 0) {
-                            error_log(
-                                __LINE__.' - Overlap is '.$overlap.': OAR hit',
-                                0
-                            );
-                        }
-                        $organs_at_risk_hit++;
-                        //show the feedback
-                        $next = 1;
-                        $comment = $answerDestination = $objAnswerTmp->selectComment(
-                            $answerId
-                        );
-                        $answerDestination = $objAnswerTmp->selectDestination(
-                            $answerId
-                        );
-                        $destination_items = explode('@@', $answerDestination);
-                        $try_hotspot = $destination_items[1];
-                        $lp_hotspot = $destination_items[2];
-                        $select_question_hotspot = $destination_items[3];
-                        $url_hotspot = $destination_items[4];
-                    }
-                }
-            }
+switch ($answerType) {
+    case MULTIPLE_ANSWER:
+        if (is_array($choiceValue)) {
+            $choiceValue = array_combine(array_values($choiceValue), array_values($choiceValue));
         }
-    }
-
-    $overlap_color = 'red';
-    if ($overlap_color) {
-        $overlap_color = 'green';
-    }
-
-    $missing_color = 'red';
-    if ($missing_color) {
-        $missing_color = 'green';
-    }
-    $excess_color = 'red';
-    if ($excess_color) {
-        $excess_color = 'green';
-    }
+        break;
+    case UNIQUE_ANSWER:
+        if (is_array($choiceValue) && isset($choiceValue[0])) {
+            $choiceValue = $choiceValue[0];
+        }
+        break;
+    case DRAGGABLE:
+        break;
+    case HOT_SPOT_DELINEATION:
+        $showResult = true;
+        if (is_array($hotSpot)) {
+            $choiceValue = isset($hotSpot[1]) ? $hotSpot[1] : '';
+            $_SESSION['exerciseResultCoordinates'][$questionId] = $choiceValue; //needed for exercise_result.php
+            $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1);
+            $answer_delineation_destination = $objAnswerTmp->selectDestination(1);
+            $_SESSION['hotspot_coord'][$questionId][1] = $delineation_cord;
+            $_SESSION['hotspot_dest'][$questionId][1] = $answer_delineation_destination;
+        }
+        break;
+    case CALCULATED_ANSWER:
+        /*$_SESSION['calculatedAnswerId'][$questionId] = mt_rand(
+            1,
+            $nbrAnswers
+        );*/
+        //var_dump($_SESSION['calculatedAnswerId'][$questionId]);
+        break;
+}
 
-    if (!is_numeric($final_overlap)) {
-        $final_overlap = 0;
+ob_start();
+$result = $objExercise->manage_answer(
+    0,
+    $questionId,
+    $choiceValue,
+    'exercise_result',
+    null,
+    false,
+    false,
+    $showResult,
+    null,
+    [],
+    true,
+    false,
+    true
+);
+$manageAnswerHtmlContent = ob_get_clean();
+$contents = '';
+$answerCorrect = false;
+if (!empty($result)) {
+    switch ($answerType) {
+        case UNIQUE_ANSWER:
+        case MULTIPLE_ANSWER:
+        case DRAGGABLE:
+        case HOT_SPOT_DELINEATION:
+        case CALCULATED_ANSWER:
+            if ($result['score'] == $result['weight']) {
+                $answerCorrect = true;
+            }
+            break;
     }
+}
 
-    if (!is_numeric($final_missing)) {
-        $final_missing = 0;
-    }
-    if (!is_numeric($final_excess)) {
-        $final_excess = 0;
+if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_DIRECT) {
+    if (isset($result['correct_answer_id'])) {
+        /** @var Answer $answer */
+        $answerId = $result['correct_answer_id'];
+        $contents = $objAnswerTmp->selectComment($answerId);
     }
-
-    if ($final_excess > 100) {
-        $final_excess = 100;
+} else {
+    $contents = Display::return_message(get_lang('Incorrect'), 'warning');
+    if ($answerCorrect) {
+        $contents = Display::return_message(get_lang('Correct'), 'success');
     }
+}
 
-    $table_resume = '<table class="data_table">
-    <tr class="row_odd">
-        <td></td>
-        <td ><b>'.get_lang('Requirements').'</b></td>
-        <td><b>'.get_lang('YourAnswer').'</b></td>
-    </tr>
-    <tr class="row_even">
-        <td><b>'.get_lang('Overlap').'</b></td>
-        <td>'.get_lang('Min').' '.$threadhold1.'</td>
-        <td><div style="color:'.$overlap_color.'">'.(($final_overlap < 0) ? 0 : intval($final_overlap)).'</div></td>
-    </tr>
-    <tr>
-        <td><b>'.get_lang('Excess').'</b></td>
-        <td>'.get_lang('Max').' '.$threadhold2.'</td>
-        <td><div style="color:'.$excess_color.'">'.(($final_excess < 0) ? 0 : intval($final_excess)).'</div></td>
-    </tr>
-
-    <tr class="row_even">
-        <td><b>'.get_lang('Missing').'</b></td>
-        <td>'.get_lang('Max').' '.$threadhold3.'</td>
-        <td><div style="color:'.$missing_color.'">'.(($final_missing < 0) ? 0 : intval($final_missing)).'</div></td>
-    </tr>
-    </table>';
+if ($answerType === HOT_SPOT_DELINEATION) {
+    $contents = $manageAnswerHtmlContent;
 }
-Session::write('newquestionList', $newQuestionList);
 $links = '';
 if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_DIRECT) {
-    if (isset($choice_value) && $choice_value == -1) {
+    if (isset($choiceValue) && $choiceValue == -1) {
         if ($answerType != HOT_SPOT_DELINEATION) {
             $links .= '<a href="#" onclick="tb_remove();">'.get_lang('ChooseAnAnswer').'</a><br />';
         }
@@ -458,34 +232,12 @@ if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_DIRECT) {
 }
 
 $destinationId = null;
-if ($answerType != HOT_SPOT_DELINEATION) {
-    if (!empty($destination)) {
-        $item_list = explode('@@', $destination);
-        $try = $item_list[0];
-        $lp = $item_list[1];
-        $destinationId = $item_list[2];
-        $url = $item_list[3];
-    }
-    $table_resume = '';
-} else {
-    $try = $try_hotspot;
-    $lp = $lp_hotspot;
-    $destinationId = $select_question_hotspot;
-    $url = $url_hotspot;
-    $exerciseResult[$questionId] = 0;
-    if ($organs_at_risk_hit == 0 && $wrong_results == false) {
-        // no error = no oar and no wrong result for delineation
-        // show if no error
-        $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers);
-        $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers);
-        // we send the error
-        $destination_items = explode('@@', $answerDestination);
-        $try = $destination_items[1];
-        $lp = $destination_items[2];
-        $destinationId = $destination_items[3];
-        $url = $destination_items[4];
-        $exerciseResult[$questionId] = 1;
-    }
+if (isset($result['answer_destination'])) {
+    $itemList = explode('@@', $result['answer_destination']);
+    $try = $itemList[0];
+    $lp = $itemList[1];
+    $destinationId = $itemList[2];
+    $url = $itemList[3];
 }
 
 // the link to retry the question
@@ -501,8 +253,6 @@ if (isset($try) && $try == 1) {
 // the link to theory (a learning path)
 if (!empty($lp)) {
     $lp_url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$lp;
-    $list = new LearnpathList(api_get_user_id());
-    $flat_list = $list->get_flat_list();
     $links .= Display:: return_icon(
         'theory.gif',
         '',
@@ -513,7 +263,7 @@ if (!empty($lp)) {
 $links .= '<br />';
 
 // the link to an external website or link
-if (!empty($url)) {
+if (!empty($url) && $url != -1) {
     $links .= Display:: return_icon(
         'link.gif',
         '',
@@ -521,10 +271,8 @@ if (!empty($url)) {
     ).'<a target="_blank" href="'.$url.'">'.get_lang('VisitUrl').'</a><br /><br />';
 }
 
-if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_POPUP) {
-    $nextQuestion = $questionNum + 1;
-    $destinationId = isset($questionList[$nextQuestion]) ? $questionList[$nextQuestion] : -1;
-}
+$nextQuestion = $questionNum + 1;
+$destinationId = isset($questionList[$nextQuestion]) ? $questionList[$nextQuestion] : -1;
 
 // the link to finish the test
 if ($destinationId == -1) {
@@ -536,8 +284,6 @@ if ($destinationId == -1) {
 } else {
     // the link to other question
     if (in_array($destinationId, $questionList)) {
-        $objQuestionTmp = Question::read($destinationId);
-        $questionName = $objQuestionTmp->selectTitle();
         $num_value_array = array_keys($questionList, $destinationId);
         $icon = Display::return_icon(
                 'quiz.png',
@@ -553,51 +299,23 @@ if ($destinationId == -1) {
 echo '<script>
 function SendEx(num) {
     if (num == -1) {
-        window.location.href = "exercise_result.php?take_session=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
+        window.location.href = "exercise_result.php?'.api_get_cidreq().'&take_session=1&exerciseId='.$exerciseId.'&num="+num+"&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
     } else {
         num -= 1;
-        window.location.href = "exercise_submit.php?tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
-    }
-    
+        window.location.href = "exercise_submit.php?'.api_get_cidreq().'&tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
+    }    
     return false;
 }
 </script>';
 
 if (!empty($links)) {
-    //echo '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>';
-    if ($answerType == HOT_SPOT_DELINEATION) {
-        if ($organs_at_risk_hit > 0) {
-            $message .= '<br />'.get_lang('ResultIs').' <b>'.get_lang('Unacceptable').'</b><br />';
-            $message .= '<p style="color:#DC0A0A;"><b>'.get_lang('OARHit').'</b></p>';
-            $message .= '<p>'.$comment.'</p>';
-        } else {
-            $message = '<p>'.get_lang('YourDelineation').'</p>';
-            $message .= $table_resume;
-            $message .= '<br />'.get_lang('ResultIs').' <b>'.$result_comment.'</b><br />';
-            $message .= '<p>'.$comment.'</p>';
-        }
-        echo '<br />';
-        echo $message;
-    } else {
-        echo '<p>'.$comment.'</p>';
-    }
+    echo '<div>'.$contents.'</div>';
     echo '<div style="padding-left: 450px"><h5>'.$links.'</h5></div>';
     echo '</div>';
-
-    Session::write('hot_spot_result', $message);
-    $_SESSION['hotspot_delineation_result'][$exerciseId][$questionId] = [$message, $exerciseResult[$questionId]];
-    // Resetting the exerciseResult variable
-    Session::write('exerciseResult', $exerciseResult);
-
-    //save this variables just in case the exercise loads an LP with other exercise
-    $_SESSION['objExerciseExtra'.$exerciseId] = $_SESSION['objExercise'];
-    $_SESSION['exerciseResultExtra'.$exerciseId] = $_SESSION['exerciseResult'];
-    $_SESSION['questionListExtra'.$exerciseId] = $_SESSION['questionList'];
 } else {
     $questionNum++;
     echo '<script>
-            window.location.href = "exercise_submit.php?exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'";
+            window.location.href = "exercise_submit.php?exerciseId='.$exerciseId.'&num='.$questionNum.'&'.api_get_cidreq().'";
         </script>';
 }
-
 echo '</div>';

+ 2 - 2
main/exercise/fill_blanks.class.php

@@ -15,8 +15,8 @@ class FillBlanks extends Question
     const FILL_THE_BLANK_MENU = 1;
     const FILL_THE_BLANK_SEVERAL_ANSWER = 2;
 
-    public static $typePicture = 'fill_in_blanks.png';
-    public static $explanationLangVar = 'FillBlanks';
+    public $typePicture = 'fill_in_blanks.png';
+    public $explanationLangVar = 'FillBlanks';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/freeanswer.class.php

@@ -12,8 +12,8 @@
  */
 class FreeAnswer extends Question
 {
-    public static $typePicture = 'open_answer.png';
-    public static $explanationLangVar = 'FreeAnswer';
+    public $typePicture = 'open_answer.png';
+    public $explanationLangVar = 'FreeAnswer';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/global_multiple_answer.class.php

@@ -8,8 +8,8 @@ use ChamiloSession as Session;
  */
 class GlobalMultipleAnswer extends Question
 {
-    public static $typePicture = 'mcmagl.png';
-    public static $explanationLangVar = 'GlobalMultipleAnswer';
+    public $typePicture = 'mcmagl.png';
+    public $explanationLangVar = 'GlobalMultipleAnswer';
 
     /**
      * GlobalMultipleAnswer constructor.

+ 2 - 49
main/exercise/hotspot.class.php

@@ -14,8 +14,8 @@
  */
 class HotSpot extends Question
 {
-    public static $typePicture = 'hotspot.png';
-    public static $explanationLangVar = 'HotSpot';
+    public $typePicture = 'hotspot.png';
+    public $explanationLangVar = 'HotSpot';
 
     /**
      * HotSpot constructor.
@@ -105,50 +105,3 @@ class HotSpot extends Question
         // nothing
     }
 }
-
-/**
- * Class HotSpotDelineation.
- */
-class HotSpotDelineation extends HotSpot
-{
-    public static $typePicture = 'hotspot-delineation.png';
-    public static $explanationLangVar = 'HotspotDelineation';
-
-    /**
-     * HotSpotDelineation constructor.
-     */
-    public function __construct()
-    {
-        parent::__construct();
-        $this->type = HOT_SPOT_DELINEATION;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function createForm(&$form, $exercise)
-    {
-        parent::createForm($form, $exercise);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function processCreation($form, $exercise)
-    {
-        parent::processCreation($form, $exercise);
-    }
-
-    public function createAnswersForm($form)
-    {
-        parent::createAnswersForm($form);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function processAnswersCreation($form, $exercise)
-    {
-        parent::processAnswersCreation($form, $exercise);
-    }
-}

+ 2 - 2
main/exercise/matching.class.php

@@ -15,8 +15,8 @@
  */
 class Matching extends Question
 {
-    public static $typePicture = 'matching.png';
-    public static $explanationLangVar = 'Matching';
+    public $typePicture = 'matching.png';
+    public $explanationLangVar = 'Matching';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer.class.php

@@ -15,8 +15,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswer extends Question
 {
-    public static $typePicture = 'mcma.png';
-    public static $explanationLangVar = 'MultipleSelect';
+    public $typePicture = 'mcma.png';
+    public $explanationLangVar = 'MultipleSelect';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer_combination.class.php

@@ -16,8 +16,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswerCombination extends Question
 {
-    public static $typePicture = 'mcmac.png';
-    public static $explanationLangVar = 'MultipleSelectCombination';
+    public $typePicture = 'mcmac.png';
+    public $explanationLangVar = 'MultipleSelectCombination';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer_combination_true_false.class.php

@@ -13,8 +13,8 @@
  */
 class MultipleAnswerCombinationTrueFalse extends MultipleAnswerCombination
 {
-    public static $typePicture = 'mcmaco.png';
-    public static $explanationLangVar = 'MultipleAnswerCombinationTrueFalse';
+    public $typePicture = 'mcmaco.png';
+    public $explanationLangVar = 'MultipleAnswerCombinationTrueFalse';
     public $options;
 
     /**

+ 2 - 2
main/exercise/multiple_answer_true_false.class.php

@@ -14,8 +14,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswerTrueFalse extends Question
 {
-    public static $typePicture = 'mcmao.png';
-    public static $explanationLangVar = 'MultipleAnswerTrueFalse';
+    public $typePicture = 'mcmao.png';
+    public $explanationLangVar = 'MultipleAnswerTrueFalse';
     public $options;
 
     /**

+ 2 - 2
main/exercise/oral_expression.class.php

@@ -12,8 +12,8 @@
  */
 class OralExpression extends Question
 {
-    public static $typePicture = 'audio_question.png';
-    public static $explanationLangVar = 'OralExpression';
+    public $typePicture = 'audio_question.png';
+    public $explanationLangVar = 'OralExpression';
     public $available_extensions = ['wav', 'ogg'];
     private $sessionId;
     private $userId;

+ 1 - 4
main/exercise/overview.php

@@ -15,10 +15,7 @@ require_once __DIR__.'/../inc/global.inc.php';
 $current_course_tool = TOOL_QUIZ;
 
 // Clear the exercise session just in case
-Session::erase('objExercise');
-Session::erase('calculatedAnswerId');
-Session::erase('duration_time_previous');
-Session::erase('duration_time');
+Exercise::cleanSessionVariables();
 
 $this_section = SECTION_COURSES;
 

+ 40 - 34
main/exercise/question.class.php

@@ -33,8 +33,8 @@ abstract class Question
     public $isContent;
     public $course;
     public $feedback;
-    public static $typePicture = 'new_question.png';
-    public static $explanationLangVar = '';
+    public $typePicture = 'new_question.png';
+    public $explanationLangVar = '';
     public $question_table_class = 'table table-striped';
     public $questionTypeWithFeedback;
     public $extra;
@@ -48,7 +48,7 @@ abstract class Question
         FREE_ANSWER => ['freeanswer.class.php', 'FreeAnswer'],
         ORAL_EXPRESSION => ['oral_expression.class.php', 'OralExpression'],
         HOT_SPOT => ['hotspot.class.php', 'HotSpot'],
-        HOT_SPOT_DELINEATION => ['hotspot.class.php', 'HotspotDelineation'],
+        HOT_SPOT_DELINEATION => ['HotSpotDelineation.php', 'HotSpotDelineation'],
         MULTIPLE_ANSWER_COMBINATION => ['multiple_answer_combination.class.php', 'MultipleAnswerCombination'],
         UNIQUE_ANSWER_NO_OPTION => ['unique_answer_no_option.class.php', 'UniqueAnswerNoOption'],
         MULTIPLE_ANSWER_TRUE_FALSE => ['multiple_answer_true_false.class.php', 'MultipleAnswerTrueFalse'],
@@ -1547,12 +1547,13 @@ abstract class Question
     /**
      * @return array
      */
-    public static function get_question_type_list()
+    public static function getQuestionTypeList()
     {
         if (api_get_setting('enable_record_audio') !== 'true') {
             self::$questionTypes[ORAL_EXPRESSION] = null;
             unset(self::$questionTypes[ORAL_EXPRESSION]);
         }
+
         if (api_get_setting('enable_quiz_scenario') !== 'true') {
             self::$questionTypes[HOT_SPOT_DELINEATION] = null;
             unset(self::$questionTypes[HOT_SPOT_DELINEATION]);
@@ -1814,33 +1815,41 @@ abstract class Question
         $exerciseId = $objExercise->id;
 
         // 1. by default we show all the question types
-        $question_type_custom_list = self::get_question_type_list();
+        $questionTypeList = self::getQuestionTypeList();
 
         if (!isset($feedbackType)) {
             $feedbackType = 0;
         }
 
-        if (in_array($feedbackType, [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP])) {
-            //2. but if it is a feedback DIRECT we only show the UNIQUE_ANSWER type that is currently available
-            $question_type_custom_list = [
-                UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
-                HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
-            ];
-        } else {
-            unset($question_type_custom_list[HOT_SPOT_DELINEATION]);
+        switch ($feedbackType) {
+            case EXERCISE_FEEDBACK_TYPE_DIRECT:
+                $questionTypeList = [
+                    UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
+                    HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
+                ];
+                break;
+            case EXERCISE_FEEDBACK_TYPE_POPUP:
+                $questionTypeList = [
+                    UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
+                    MULTIPLE_ANSWER => self::$questionTypes[MULTIPLE_ANSWER],
+                    DRAGGABLE => self::$questionTypes[DRAGGABLE],
+                    HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
+                    CALCULATED_ANSWER => self::$questionTypes[CALCULATED_ANSWER],
+                ];
+                break;
+            default:
+                unset($questionTypeList[HOT_SPOT_DELINEATION]);
+                break;
         }
 
         echo '<div class="panel panel-default">';
         echo '<div class="panel-body">';
         echo '<ul class="question_menu">';
-        foreach ($question_type_custom_list as $i => $a_type) {
-            // @todo remove require_once classes are already loaded using composer
-            // include the class of the type
-            require_once $a_type[0];
-            // get the picture of the type and the langvar which describes it
-            $img = $explanation = '';
-            eval('$img = '.$a_type[1].'::$typePicture;');
-            eval('$explanation = get_lang('.$a_type[1].'::$explanationLangVar);');
+        foreach ($questionTypeList as $i => $type) {
+            /** @var Question $type */
+            $type = new $type[1]();
+            $img = $type->getTypePicture();
+            $explanation = get_lang($type->getExplanation());
             echo '<li>';
             echo '<div class="icon-image">';
             $icon = '<a href="admin.php?'.api_get_cidreq().'&newQuestion=yes&answerType='.$i.'">'.
@@ -1853,7 +1862,6 @@ abstract class Question
                     $icon = Display::return_icon($img, $explanation, null, ICON_SIZE_BIG);
                 }
             }
-
             echo $icon;
             echo '</div>';
             echo '</li>';
@@ -2198,26 +2206,24 @@ abstract class Question
     }
 
     /**
-     * @return array the image filename of the question type
+     * @return string
      */
-    public function get_type_icon_html()
+    public function getTypePicture()
     {
-        $type = $this->selectType();
-        $tabQuestionList = self::get_question_type_list(); // [0]=file to include [1]=type name
-
-        require_once $tabQuestionList[$type][0];
-
-        $img = $explanation = null;
-        eval('$img = '.$tabQuestionList[$type][1].'::$typePicture;');
-        eval('$explanation = get_lang('.$tabQuestionList[$type][1].'::$explanationLangVar);');
+        return $this->typePicture;
+    }
 
-        return [$img, $explanation];
+    /**
+     * @return string
+     */
+    public function getExplanation()
+    {
+        return $this->explanationLangVar;
     }
 
     /**
      * Get course medias.
      *
-     * @param int course id
      * @param int $course_id
      *
      * @return array

+ 1 - 1
main/exercise/question_admin.inc.php

@@ -32,7 +32,7 @@ if (is_object($objQuestion)) {
         $type = $_REQUEST['answerType'];
     }
 
-    $typesInformation = Question::get_question_type_list();
+    $typesInformation = Question::getQuestionTypeList();
     $form_title_extra = isset($typesInformation[$type][1]) ? get_lang($typesInformation[$type][1]) : null;
 
     $code = '';

+ 2 - 2
main/exercise/question_create.php

@@ -31,7 +31,7 @@ $form = new FormValidator('add_question', 'post', api_get_self().'?'.api_get_cid
 // form title
 $form->addElement('header', '', get_lang('AddQuestionToExercise'));
 
-$question_list = Question::get_question_type_list();
+$question_list = Question::getQuestionTypeList();
 $question_list_options = [];
 foreach ($question_list as $key => $value) {
     $question_list_options[$key] = addslashes(get_lang($value[1]));
@@ -117,7 +117,7 @@ if ($form->validate()) {
 
 function check_question_type($parameter)
 {
-    $question_list = Question::get_question_type_list();
+    $question_list = Question::getQuestionTypeList();
     foreach ($question_list as $key => $value) {
         $valid_question_types[] = $key;
     }

+ 5 - 3
main/exercise/question_list_admin.inc.php

@@ -59,12 +59,12 @@ $ajax_url = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&
             $("#dialog-confirm").dialog({
                 modal: true,
                 buttons: {
-                    "<?php echo get_lang("Yes"); ?>": function () {
+                    "<?php echo get_lang('Yes'); ?>": function () {
                         location.href = targetUrl;
                         $(this).dialog("close");
 
                     },
-                    "<?php echo get_lang("No"); ?>": function () {
+                    "<?php echo get_lang('No'); ?>": function () {
                         $(this).dialog("close");
                     }
                 }
@@ -308,7 +308,9 @@ if (!$inATest) {
                     </a>';
 
                 // Question type
-                list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html();
+                $typeImg = $objQuestionTmp->getTypePicture();
+                $typeExpl = $objQuestionTmp->getExplanation();
+
                 $questionType = Display::return_icon($typeImg, $typeExpl);
 
                 // Question category

+ 6 - 4
main/exercise/question_pool.php

@@ -472,7 +472,7 @@ $select_difficulty_html = Display::select(
 echo Display::form_row(get_lang('Difficulty'), $select_difficulty_html);
 
 // Answer type
-$question_list = Question::get_question_type_list();
+$question_list = Question::getQuestionTypeList();
 
 $new_question_list = [];
 $new_question_list['-1'] = get_lang('All');
@@ -1177,10 +1177,12 @@ function get_action_icon_for_question(
 function get_question_type_for_question($in_selectedcourse, $in_questionid)
 {
     $courseInfo = api_get_course_info_by_id($in_selectedcourse);
-    $myObjQuestion = Question::read($in_questionid, $courseInfo);
+    $question = Question::read($in_questionid, $courseInfo);
     $questionType = null;
-    if (!empty($myObjQuestion)) {
-        list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html();
+    if (!empty($question)) {
+        $typeImg = $question->getTypePicture();
+        $typeExpl = $question->getExplanation();
+
         $questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, [], 32), []);
     }
 

+ 5 - 11
main/exercise/unique_answer.class.php

@@ -18,8 +18,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswer extends Question
 {
-    public static $typePicture = 'mcua.png';
-    public static $explanationLangVar = 'UniqueSelect';
+    public $typePicture = 'mcua.png';
+    public $explanationLangVar = 'UniqueSelect';
 
     /**
      * Constructor.
@@ -37,6 +37,7 @@ class UniqueAnswer extends Question
     public function createAnswersForm($form)
     {
         // Getting the exercise list
+        /** @var Exercise $obj_ex */
         $obj_ex = Session::read('objExercise');
 
         $editor_config = [
@@ -50,13 +51,6 @@ class UniqueAnswer extends Question
         $nb_answers = isset($_POST['nb_answers']) ? (int) $_POST['nb_answers'] : 4;
         $nb_answers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0));
 
-        /*
-          Types of Feedback
-          $feedback_option[0]=get_lang('Feedback');
-          $feedback_option[1]=get_lang('DirectFeedback');
-          $feedback_option[2]=get_lang('NoFeedback');
-         */
-
         $feedback_title = '';
         switch ($obj_ex->getFeedbackType()) {
             case EXERCISE_FEEDBACK_TYPE_DIRECT:
@@ -99,8 +93,8 @@ class UniqueAnswer extends Question
         }
         $form->addElement('hidden', 'nb_answers');
 
-        //Feedback SELECT
-        $question_list = $obj_ex->selectQuestionList();
+        $obj_ex->setQuestionList(true);
+        $question_list = $obj_ex->getQuestionList();
         $select_question = [];
         $select_question[0] = get_lang('SelectTargetQuestion');
         if (is_array($question_list)) {

+ 2 - 2
main/exercise/unique_answer_no_option.class.php

@@ -15,8 +15,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswerNoOption extends Question
 {
-    public static $typePicture = 'mcuao.png';
-    public static $explanationLangVar = 'UniqueAnswerNoOption';
+    public $typePicture = 'mcuao.png';
+    public $explanationLangVar = 'UniqueAnswerNoOption';
 
     /**
      * Constructor.

+ 2 - 4
main/inc/ajax/exercise.ajax.php

@@ -549,7 +549,7 @@ switch ($action) {
                     $hotspot_delineation_result = $_SESSION['hotspot_delineation_result'][$objExercise->selectId()][$my_question_id];
                 }
 
-                if ($type == 'simple') {
+                if ($type === 'simple') {
                     // Getting old attempt in order to decrees the total score.
                     $old_result = $objExercise->manage_answer(
                         $exeId,
@@ -560,10 +560,8 @@ switch ($action) {
                         false,
                         true,
                         false,
-                        $objExercise->selectPropagateNeg(),
-                        []
+                        $objExercise->selectPropagateNeg()
                     );
-
                     // Removing old score.
                     $total_score = $total_score - $old_result['score'];
                 }

+ 0 - 1
main/inc/lib/exercise.lib.php

@@ -4413,7 +4413,6 @@ EOT;
         // Hide results
         $show_results = false;
         $show_only_score = false;
-
         if (in_array($objExercise->results_disabled,
             [
                 RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,

+ 17 - 13
main/inc/lib/geometry.lib.php

@@ -6,6 +6,7 @@
  * @package chamilo.include.geometry
  */
 define('DEBUG', false);
+
 /**
  * poly_init -    build the array which will store the image of the polygone.
  *
@@ -52,7 +53,6 @@ function poly_compile($poly, $max, $test = false)
     // looking for EDGES
     // may be optimized by a dynamic choice
     // between Y and X based on max[y]<max[x]
-
     /*
      * bords    cointains the edges of the polygone
      *        it is an array of array,
@@ -66,7 +66,6 @@ function poly_compile($poly, $max, $test = false)
         $bord_lenght = $max['y'];
     }
 
-    //$bords = array_fill(0, $bord_lenght-1, array()); // building this array
     $bords = array_fill(0, $bord_lenght, []); // building this array
 
     /* adding the first point of the polygone */
@@ -78,7 +77,7 @@ function poly_compile($poly, $max, $test = false)
     $i = 1; // we re-use $i and $old_pente bellow the loop
     $old_pente = 0;
     // for each points of the polygon but the first
-    for (; $i < sizeof($poly) && (!empty($poly[$i]['x']) && !empty($poly[$i]['y'])); $i++) {
+    for (; $i < count($poly) && (!empty($poly[$i]['x']) && !empty($poly[$i]['y'])); $i++) {
         /* special cases */
         if ($poly[$i - 1]['y'] == $poly[$i]['y']) {
             if ($poly[$i - 1]['x'] == $poly[$i]['x']) {
@@ -95,9 +94,15 @@ function poly_compile($poly, $max, $test = false)
 
         //echo 'point:'.$poly[$i]['y']; bug here
         // adding the point as a part of an edge
-        if (is_array($bords[$poly[$i]['y']])) { //avoid warning
-        array_push($bords[$poly[$i]['y']], $poly[$i]['x']);
+        if (isset($poly[$i]) &&
+            isset($poly[$i]['y']) &&
+            isset($bords[$poly[$i]['y']]) &&
+            is_array($bords[$poly[$i]['y']])
+        ) {
+            // Avoid warning
+            array_push($bords[$poly[$i]['y']], $poly[$i]['x']);
         }
+
         if (DEBUG) {
             echo '('.$poly[$i]['x'].';'.$poly[$i]['y'].')   ';
         }
@@ -113,7 +118,10 @@ function poly_compile($poly, $max, $test = false)
         if ($i > 1) {
             if (($old_pente < 0 && $pente > 0)
                 || ($old_pente > 0 && $pente < 0)) {
-                if (is_array($bords[$poly[$i]['y']])) { //avoid warning
+                if (isset($poly[$i]) && isset($poly[$i]['y']) &&
+                    isset($bords[$poly[$i]['y']]) &&
+                    is_array($bords[$poly[$i]['y']])
+                ) {
                     array_push($bords[$poly[$i]['y']], $poly[$i]['x']);
                 }
 
@@ -127,9 +135,6 @@ function poly_compile($poly, $max, $test = false)
         /* detect the direction of the elevation in Y */
         $dy_inc = ($poly[$i]['y'] - $poly[$i - 1]['y']) > 0 ? 1 : -1;
         $x = $poly[$i - 1]['x'];
-//        if (DEBUG) echo "init: ".$poly[$i-1]['y']."  dy_inc: ".$dy_inc.
-//            "   end: ".$poly[$i]['y']."   pente:".$pente;
-
         /* computing points between $poly[$i-1]['y'] and $poly[$i-1]['y'] */
 
         // we iterate w/ $dy in ]$poly[$i-1]['y'],$poly[$i-1]['y'][
@@ -139,13 +144,13 @@ function poly_compile($poly, $max, $test = false)
             $dy += $dy_inc) {
             $x += $pente * $dy_inc;
             array_push($bords[$dy], $x);
-//            if (DEBUG) echo '/('.$x.';'.$dy.')   ';
         }
         $old_pente = $pente;
     }
 
     // closing the polygone (the edge between $poly[$i-1] and $poly[0])
-    if ($poly[$i - 1]['y'] != $poly[0]['y']) {// droite--> rien à faire
+    if ($poly[$i - 1]['y'] != $poly[0]['y']) {
+        // droite--> rien à faire
         // elevation between $poly[0]['x'] and $poly[1]['x'])
         $rest = $poly[0]['y'] - $poly[1]['y'];
         if ($rest != 0) {
@@ -193,12 +198,11 @@ function poly_compile($poly, $max, $test = false)
         For each pair of point, we color the points in between */
     $n = count($bords);
     for ($i = 0; $i < $n; $i++) {  // Y
-        //error_log(__FILE__.' - Border Num '.$i,0);
         if (is_array($bords[$i])) {
             sort($bords[$i]);
         }
 
-        for ($j = 0; $j < sizeof($bords[$i]); $j += 2) { // bords
+        for ($j = 0; $j < count($bords[$i]); $j += 2) { // bords
             if (!isset($bords[$i][$j + 1])) {
                 continue;
             }

+ 5 - 6
main/inc/lib/internationalization.lib.php

@@ -466,14 +466,13 @@ function api_get_utc_datetime(
  * Returns a DATETIME string converted to the right timezone.
  *
  * @param mixed  $time                    The time to be converted
- * @param string $to_timezone             The timezone to be converted to.
- *                                        If null, the timezone will be determined based on user preference,
+ * @param string $to_timezone             If null, the timezone will be determined based on user preference,
  *                                        or timezone chosen by the admin for the platform.
  * @param string $from_timezone           The timezone to be converted from. If null, UTC will be assumed.
- * @param bool   $returnNullIfInvalidDate
- * @param bool   $showTime
- * @param bool   $humanForm
- * @param string $format
+ * @param bool   $returnNullIfInvalidDate Return null if date is not correct.
+ * @param bool   $showTime                Show time.
+ * @param bool   $humanForm               Return a readable date time.
+ * @param string $format                  Specify format.
  *
  * @return string The converted time formatted as Y-m-d H:i:s
  *