소스 검색

Add setting "score_grade_model" see BT#12898

Allow to convert a score into a text/color label
using a model if score is inside those values.

WIP: This change only affects exercises.
jmontoyaa 7 년 전
부모
커밋
33debc5659
6개의 변경된 파일197개의 추가작업 그리고 31개의 파일을 삭제
  1. 11 0
      main/course_info/infocours.php
  2. 29 11
      main/exercise/exercise_show.php
  3. 8 2
      main/exercise/question.class.php
  4. 4 0
      main/inc/lib/course.lib.php
  5. 99 15
      main/inc/lib/exercise.lib.php
  6. 46 3
      main/install/configuration.dist.php

+ 11 - 0
main/course_info/infocours.php

@@ -167,6 +167,16 @@ if (api_get_setting('allow_course_theme') == 'true') {
 }
 
 $form->addElement('label', get_lang('DocumentQuota'), format_file_size(DocumentManager::get_course_quota()));
+
+if (!empty(ExerciseLib::getScoreModels())) {
+    $models = ExerciseLib::getScoreModels();
+    $options = ['' => get_lang('None')];
+    foreach ($models['models'] as $item) {
+        $options[$item['id']] = get_lang($item['name']);
+    }
+    $form->addSelect('score_model_id', get_lang('ScoreModel'), $options);
+}
+
 $form->addButtonSave(get_lang('SaveSettings'), 'submit_save');
 $form->addHtml('
         </div>
@@ -636,6 +646,7 @@ $values['legal'] = $all_course_information['legal'];
 $values['activate_legal'] = $all_course_information['activate_legal'];
 
 $courseSettings = CourseManager::getCourseSettingVariables($appPlugin);
+
 foreach ($courseSettings as $setting) {
     $result = api_get_course_setting($setting);
     if ($result != '-1') {

+ 29 - 11
main/exercise/exercise_show.php

@@ -140,7 +140,7 @@ if (isset($_SESSION['gradebook'])) {
 }
 
 $allowRecordAudio = api_get_setting('enable_record_audio') === 'true';
-$allowTeacherComentAudio = api_get_configuration_value('allow_teacher_comment_audio') === true;
+$allowTeacherCommentAudio = api_get_configuration_value('allow_teacher_comment_audio') === true;
 
 if (!empty($gradebook) && $gradebook == 'view') {
     $interbreadcrumb[] = array(
@@ -162,7 +162,7 @@ $htmlHeadXtra[] = '<link rel="stylesheet" href="'.api_get_path(WEB_LIBRARY_JS_PA
 $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/js/hotspot.js"></script>';
 $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'annotation/js/annotation.js"></script>';
 
-if ($allowRecordAudio && $allowTeacherComentAudio) {
+if ($allowRecordAudio && $allowTeacherCommentAudio) {
     $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'rtc/RecordRTC.js"></script>';
     $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_PATH).'wami-recorder/recorder.js"></script>';
     $htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_PATH).'wami-recorder/gui.js"></script>';
@@ -202,7 +202,7 @@ if ($origin != 'learnpath') {
                 oHidn.type = "hidden";
                 var selname = oHidn.name = "marks_" + m_id[i];
                 var selid = document.forms['marksform_' + m_id[i]].marks.selectedIndex;
-                oHidn.value = document.forms['marksform_' + m_id[i]].marks.options[selid].text;
+                oHidn.value = document.forms['marksform_' + m_id[i]].marks.options[selid].value;
                 f.appendChild(oHidn);
             }
 
@@ -721,7 +721,7 @@ foreach ($questionList as $questionId) {
             echo '</p>';
 
             echo '<div id="feedback_'.$name.'" class="show">';
-            $comnt = trim(Event::get_comments($id, $questionId));
+            $comnt = Event::get_comments($id, $questionId);
             if (!empty($comnt)) {
                 echo ExerciseLib::getFeedbackText($comnt);
                 echo ExerciseLib::getOralFeedbackAudio($id, $questionId, $student_id);
@@ -729,7 +729,7 @@ foreach ($questionList as $questionId) {
             echo '</div>';
 
             echo '<div id="'.$name.'" class="row hidden">';
-            echo '<div class="col-sm-'.($allowTeacherComentAudio ? 7 : 12).'">';
+            echo '<div class="col-sm-'.($allowTeacherCommentAudio ? 7 : 12).'">';
 
             $arrid[] = $questionId;
             $feedback_form = new FormValidator('frmcomments'.$questionId);
@@ -759,7 +759,7 @@ foreach ($questionList as $questionId) {
 
             echo '</div>';
 
-            if ($allowRecordAudio && $allowTeacherComentAudio) {
+            if ($allowRecordAudio && $allowTeacherCommentAudio) {
                 echo '<div class="col-sm-5">';
                 echo ExerciseLib::getOralFeedbackForm($id, $questionId, $student_id);
                 echo '</div>';
@@ -780,13 +780,31 @@ foreach ($questionList as $questionId) {
         if ($is_allowedToEdit && $isFeedbackAllowed) {
             if (in_array($answerType, array(FREE_ANSWER, ORAL_EXPRESSION, ANNOTATION))) {
                 $marksname = "marksName".$questionId;
+                $arrmarks[] = $questionId;
+
                 echo '<div id="'.$marksname.'" class="hidden">';
+                // @todo use FormValidator
+                /*$formMark = new FormValidator("marksform_'.$questionId.'", 'post');
+                $options = [
+                  1,
+                  2
+                ];
+                $formMark->addSelect('marks', get_lang('AssignMarks'), $options);
+                $formMark->display();*/
                 echo '<form name="marksform_'.$questionId.'" method="post" action="">';
-                $arrmarks[] = $questionId;
                 echo get_lang("AssignMarks");
-                echo "&nbsp;<select name='marks' id='marks'>";
-                for ($i = 0; $i <= $questionWeighting; $i++) {
-                    echo '<option '.(($i == $questionScore) ? "selected='selected'" : '').'>'.$i.'</option>';
+                echo "&nbsp;<select class='selectpicker' name='marks' id='marks'>";
+                $model = ExerciseLib::getCourseScoreModel();
+                if (empty($model)) {
+                    for ($i = 0; $i <= $questionWeighting; $i++) {
+                        echo '<option value="'.$i.'" '.(($i == $questionScore) ? "selected='selected'" : '').'>'.$i.'</option>';
+                    }
+                } else {
+                    foreach ($model['score_list'] as $item) {
+                        $i = api_number_format($item['score_to_qualify']/100 * $questionWeighting, 2);
+                        $model = ExerciseLib::getModelStyle($item, $i);
+                        echo '<option value="'.$i.'" '.(($i == $questionScore) ? "selected='selected'" : '').'>'.$model.'</option>';
+                    }
                 }
                 echo '</select>';
                 echo '</form><br /></div>';
@@ -801,7 +819,7 @@ foreach ($questionList as $questionId) {
                     <div id="'.$marksname.'" class="hidden">
                         <form name="marksform_'.$questionId.'" method="post" action="">
                             <select name="marks" id="marks" style="display:none;">
-                                <option>'.$questionScore.'</option>
+                                <option value="'.$questionScore.'" >'.$questionScore.'</option>
                             </select>
                         </form>
                         <br/>

+ 8 - 2
main/exercise/question.class.php

@@ -1945,6 +1945,10 @@ abstract class Question
                 $class = 'warning';
                 $weight = float_format($score['weight'], 1);
                 $score['result'] = " ? / ".$weight;
+                $model = ExerciseLib::getCourseScoreModel();
+                if (!empty($model)) {
+                    $score['result'] = " ? ";
+                }
             }
         }
 
@@ -2219,8 +2223,10 @@ abstract class Question
     public function isQuestionWaitingReview($score)
     {
         $isReview = false;
-        if (!empty($score['comments']) || $score['score'] > 0) {
-            $isReview = true;
+        if (!empty($score)) {
+            if (!empty($score['comments']) || $score['score'] > 0) {
+                $isReview = true;
+            }
         }
 
         return $isReview;

+ 4 - 0
main/inc/lib/course.lib.php

@@ -5379,6 +5379,10 @@ class CourseManager
             'show_course_in_user_language'
         );
 
+        if (!empty(ExerciseLib::getScoreModels())) {
+            $courseSettings[] = 'score_model_id';
+        }
+
         $allowLPReturnLink = api_get_setting('allow_lp_return_link');
         if ($allowLPReturnLink === 'true') {
             $courseSettings[] = 'lp_return_link';

+ 99 - 15
main/inc/lib/exercise.lib.php

@@ -2285,17 +2285,17 @@ HOTSPOT;
             return '-';
         }
 
-        $max_note = api_get_setting('exercise_max_score');
-        $min_note = api_get_setting('exercise_min_score');
+        $maxNote = api_get_setting('exercise_max_score');
+        $minNote = api_get_setting('exercise_min_score');
 
         if ($use_platform_settings) {
-            if ($max_note != '' && $min_note != '') {
+            if ($maxNote != '' && $minNote != '') {
                 if (!empty($weight) && intval($weight) != 0) {
-                    $score = $min_note + ($max_note - $min_note) * $score / $weight;
+                    $score = $minNote + ($maxNote - $minNote) * $score / $weight;
                 } else {
-                    $score = $min_note;
+                    $score = $minNote;
                 }
-                $weight = $max_note;
+                $weight = $maxNote;
             }
         }
         $percentage = (100 * $score) / ($weight != 0 ? $weight : 1);
@@ -2305,7 +2305,7 @@ HOTSPOT;
         $score = float_format($score, 1);
         $weight = float_format($weight, 1);
 
-        $html = null;
+        $html = '';
         if ($show_percentage) {
             $parent = '('.$score.' / '.$weight.')';
             $html = $percentage."%  $parent";
@@ -2315,11 +2315,91 @@ HOTSPOT;
         } else {
             $html = $score.' / '.$weight;
         }
-        $html = Display::span($html, array('class' => 'score_exercise'));
+
+        // Over write score
+        $scoreBasedInModel = self::convertScoreToModel($percentage);
+        if (!empty($scoreBasedInModel)) {
+            $html = $scoreBasedInModel;
+        }
+
+        $html = Display::span($html, ['class' => 'score_exercise']);
 
         return $html;
     }
 
+    /**
+     * @param array $model
+     * @param float $percentage
+     * @return string
+     */
+    public static function getModelStyle($model, $percentage)
+    {
+        $modelWithStyle = get_lang($model['name']);
+        $modelWithStyle .= ' - <span class="'.$model['css_class'].'">'.$model['css_class'].' </span> - ';
+        $modelWithStyle .= $percentage;
+
+        return $modelWithStyle;
+    }
+
+    /**
+     * @param float $percentage value between 0 and 100
+     * @return string
+     */
+    public static function convertScoreToModel($percentage)
+    {
+        $model = self::getCourseScoreModel();
+        if (!empty($model)) {
+            $scoreWithGrade = [];
+            foreach ($model['score_list'] as $item) {
+                if ($percentage >= $item['min']  && $percentage <= $item['max']) {
+                    $scoreWithGrade = $item;
+                    break;
+                }
+            }
+
+            if (!empty($scoreWithGrade)) {
+                return self::getModelStyle($scoreWithGrade, $percentage);
+            }
+        }
+        return '';
+    }
+
+    /**
+     * @return array
+     */
+    public static function getCourseScoreModel()
+    {
+        $modelList = self::getScoreModels();
+        if (empty($modelList)) {
+            return [];
+        }
+
+        $courseInfo = api_get_course_info();
+        if (!empty($courseInfo)) {
+            $scoreModelId = api_get_course_setting('score_model_id');
+            if ($scoreModelId != -1) {
+                $modelIdList = array_column($modelList['models'], 'id');
+                if (in_array($scoreModelId, $modelIdList)) {
+                    foreach ($modelList['models'] as $item) {
+                        if ($item['id'] == $scoreModelId) {
+                            return $item;
+                        }
+                    }
+                }
+            }
+        }
+
+        return [];
+    }
+
+    /**
+     * @return array
+     */
+    public static function getScoreModels()
+    {
+        return api_get_configuration_value('score_grade_model');
+    }
+
     /**
      * @param float $score
      * @param float $weight
@@ -2421,15 +2501,15 @@ HOTSPOT;
      */
     public static function convert_score($score, $weight)
     {
-        $max_note = api_get_setting('exercise_max_score');
-        $min_note = api_get_setting('exercise_min_score');
+        $maxNote = api_get_setting('exercise_max_score');
+        $minNote = api_get_setting('exercise_min_score');
 
         if ($score != '' && $weight != '') {
-            if ($max_note != '' && $min_note != '') {
+            if ($maxNote != '' && $minNote != '') {
                 if (!empty($weight)) {
-                    $score = $min_note + ($max_note - $min_note) * $score / $weight;
+                    $score = $minNote + ($maxNote - $minNote) * $score / $weight;
                 } else {
-                    $score = $min_note;
+                    $score = $minNote;
                 }
             }
         }
@@ -3859,7 +3939,11 @@ HOTSPOT;
                 $comnt = null;
                 if ($show_results) {
                     $comnt = Event::get_comments($exe_id, $questionId);
-                    $teacherAudio = ExerciseLib::getOralFeedbackAudio($exe_id, $questionId, api_get_user_id());;
+                    $teacherAudio = ExerciseLib::getOralFeedbackAudio(
+                        $exe_id,
+                        $questionId,
+                        api_get_user_id()
+                    );;
 
                     if (!empty($comnt) || $teacherAudio) {
                         echo '<b>'.get_lang('Feedback').'</b>';
@@ -3914,8 +3998,8 @@ HOTSPOT;
                 if ($show_results) {
                     $question_content .= '</div>';
                 }
-
                 $exercise_content .= Display::panel($question_content);
+
             } // end foreach() block that loops over all questions
         }
 

+ 46 - 3
main/install/configuration.dist.php

@@ -500,7 +500,8 @@ $_configuration['send_all_emails_to'] = [
     ]
 ];*/
 //
-// ------ Exercises configuration settings
+
+// Exercises configuration settings
 // Send only quiz answer notifications to course coaches and not general coach
 //$_configuration['block_quiz_mail_notification_general_coach'] = false;
 // Show question feedback (requires DB change: "ALTER TABLE c_quiz_question ADD COLUMN feedback text;")
@@ -510,10 +511,52 @@ $_configuration['send_all_emails_to'] = [
 //$_configuration['allow_quiz_show_previous_button_setting'] = false;
 // Allow to teachers review exercises question with audio notes
 //$_configuration["allow_teacher_comment_audio"] = false;
-// ------
+
 // Hide search form in session list
 //$_configuration['hide_search_form_in_session_list'] = false;
 // Allow exchange of messages from teachers/bosses about a user.
 //$_configuration['private_messages_about_user'] = false;
 
-
+// Score model
+// Allow to convert a score into a text/color label
+// using a model if score is inside those values. See BT#12898
+/*
+$_configuration['score_grade_model'] = [
+    'models' => [
+        [
+            'id' => 1,
+            'name' => 'ThisIsMyModel', // Value will be translated using get_lang
+            'score_list' => [
+                [
+                    'name' => 'VeryBad', // Value will be translated using get_lang
+                    'css_class' => 'btn-danger',
+                    'min' => 0,
+                    'max' => 20,
+                    'score_to_qualify' => 0
+                ],
+                [
+                    'name' => 'Bad',
+                    'css_class' => 'btn-danger',
+                    'min' => 21,
+                    'max' => 50,
+                    'score_to_qualify' => 25
+                ],
+                [
+                    'name' => 'Good',
+                    'css_class' => 'btn-warning',
+                    'min' => 51,
+                    'max' => 70,
+                    'score_to_qualify' => 60
+                ],
+                [
+                    'name' => 'VeryGood',
+                    'css_class' => 'btn-success',
+                    'min' => 71,
+                    'max' => 100,
+                    'score_to_qualify' => 100
+                ]
+            ]
+        ]
+    ]
+];
+*/