|
1
|
|
|
<?php |
|
2
|
|
|
/* For licensing terms, see /license.txt */ |
|
3
|
|
|
|
|
4
|
|
|
use ChamiloSession as Session; |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* Exercise result |
|
8
|
|
|
* This script gets information from the script "exercise_submit.php", |
|
9
|
|
|
* through the session, and calculates the score of the student for |
|
10
|
|
|
* that exercise. |
|
11
|
|
|
* Then it shows the results on the screen. |
|
12
|
|
|
* |
|
13
|
|
|
* @package chamilo.exercise |
|
14
|
|
|
* |
|
15
|
|
|
* @author Olivier Brouckaert, main author |
|
16
|
|
|
* @author Roan Embrechts, some refactoring |
|
17
|
|
|
* @author Julio Montoya switchable fill in blank option added |
|
18
|
|
|
* |
|
19
|
|
|
* @todo split more code up in functions, move functions to library? |
|
20
|
|
|
*/ |
|
21
|
|
|
$debug = false; |
|
22
|
|
|
require_once __DIR__.'/../inc/global.inc.php'; |
|
23
|
|
|
|
|
24
|
|
|
$this_section = SECTION_COURSES; |
|
25
|
|
|
|
|
26
|
|
|
/* ACCESS RIGHTS */ |
|
27
|
|
|
api_protect_course_script(true); |
|
28
|
|
|
|
|
29
|
|
|
if ($debug) { |
|
30
|
|
|
error_log('Entering exercise_result.php: '.print_r($_POST, 1)); |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
$origin = api_get_origin(); |
|
34
|
|
|
|
|
35
|
|
|
/** @var Exercise $objExercise */ |
|
36
|
|
|
if (empty($objExercise)) { |
|
37
|
|
|
$objExercise = Session::read('objExercise'); |
|
38
|
|
|
} |
|
39
|
|
|
if (empty($remind_list)) { |
|
40
|
|
|
$remind_list = isset($_REQUEST['remind_list']) ? $_REQUEST['remind_list'] : null; |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
|
|
$exe_id = isset($_REQUEST['exe_id']) ? (int) $_REQUEST['exe_id'] : 0; |
|
44
|
|
|
|
|
45
|
|
|
if (empty($objExercise)) { |
|
46
|
|
|
// Redirect to the exercise overview |
|
47
|
|
|
// Check if the exe_id exists |
|
48
|
|
|
$objExercise = new Exercise(); |
|
49
|
|
|
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id); |
|
50
|
|
|
if (!empty($exercise_stat_info) && isset($exercise_stat_info['exe_exo_id'])) { |
|
51
|
|
|
header('Location: overview.php?exerciseId='.$exercise_stat_info['exe_exo_id'].'&'.api_get_cidreq()); |
|
52
|
|
|
exit; |
|
53
|
|
|
} |
|
54
|
|
|
api_not_allowed(true); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
$js = '<script>'.api_get_language_translate_html().'</script>'; |
|
58
|
|
|
$htmlHeadXtra[] = $js; |
|
59
|
|
|
|
|
60
|
|
|
if (api_is_in_gradebook()) { |
|
61
|
|
|
$interbreadcrumb[] = [ |
|
62
|
|
|
'url' => Category::getUrl(), |
|
63
|
|
|
'name' => get_lang('ToolGradebook'), |
|
64
|
|
|
]; |
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
$nameTools = get_lang('Exercises'); |
|
68
|
|
|
|
|
69
|
|
|
$interbreadcrumb[] = [ |
|
70
|
|
|
'url' => 'exercise.php?'.api_get_cidreq(), |
|
71
|
|
|
'name' => get_lang('Exercises'), |
|
72
|
|
|
]; |
|
73
|
|
|
|
|
74
|
|
|
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/js/hotspot.js"></script>'; |
|
75
|
|
|
$htmlHeadXtra[] = '<link rel="stylesheet" href="'.api_get_path(WEB_LIBRARY_JS_PATH).'hotspot/css/hotspot.css">'; |
|
76
|
|
|
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'annotation/js/annotation.js"></script>'; |
|
77
|
|
|
if (api_get_configuration_value('quiz_prevent_copy_paste')) { |
|
78
|
|
|
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_LIBRARY_JS_PATH).'jquery.nocopypaste.js"></script>'; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
if (!in_array($origin, ['learnpath', 'embeddable'])) { |
|
82
|
|
|
// So we are not in learnpath tool |
|
83
|
|
|
Display::display_header($nameTools, get_lang('Exercise')); |
|
84
|
|
|
} else { |
|
85
|
|
|
$htmlHeadXtra[] = " |
|
86
|
|
|
<style> |
|
87
|
|
|
body { background: none;} |
|
88
|
|
|
</style> |
|
89
|
|
|
"; |
|
90
|
|
|
Display::display_reduced_header(); |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
// I'm in a preview mode as course admin. Display the action menu. |
|
94
|
|
|
if (api_is_course_admin() && !in_array($origin, ['learnpath', 'embeddable'])) { |
|
95
|
|
|
echo '<div class="actions">'; |
|
96
|
|
|
echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id.'">'. |
|
97
|
|
|
Display::return_icon('back.png', get_lang('GoBackToQuestionList'), [], 32).'</a>'; |
|
98
|
|
|
echo '<a href="exercise_admin.php?'.api_get_cidreq().'&modifyExercise=yes&exerciseId='.$objExercise->id.'">'. |
|
99
|
|
|
Display::return_icon('edit.png', get_lang('ModifyExercise'), [], 32).'</a>'; |
|
100
|
|
|
echo '</div>'; |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
$feedback_type = $objExercise->feedback_type; |
|
104
|
|
|
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id); |
|
105
|
|
|
|
|
106
|
|
|
if (!empty($exercise_stat_info['data_tracking'])) { |
|
107
|
|
|
$question_list = explode(',', $exercise_stat_info['data_tracking']); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
$learnpath_id = isset($exercise_stat_info['orig_lp_id']) ? $exercise_stat_info['orig_lp_id'] : 0; |
|
111
|
|
|
$learnpath_item_id = isset($exercise_stat_info['orig_lp_item_id']) ? $exercise_stat_info['orig_lp_item_id'] : 0; |
|
112
|
|
|
$learnpath_item_view_id = isset($exercise_stat_info['orig_lp_item_view_id']) ? $exercise_stat_info['orig_lp_item_view_id'] : 0; |
|
113
|
|
|
|
|
114
|
|
|
if ($origin == 'learnpath') { |
|
115
|
|
|
?> |
|
116
|
|
|
<form method="GET" action="exercise.php?<?php echo api_get_cidreq(); ?>"> |
|
117
|
|
|
<input type="hidden" name="origin" value="<?php echo $origin; ?>" /> |
|
118
|
|
|
<input type="hidden" name="learnpath_id" value="<?php echo $learnpath_id; ?>" /> |
|
119
|
|
|
<input type="hidden" name="learnpath_item_id" value="<?php echo $learnpath_item_id; ?>"/> |
|
120
|
|
|
<input type="hidden" name="learnpath_item_view_id" value="<?php echo $learnpath_item_view_id; ?>" /> |
|
121
|
|
|
<?php |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
$i = $total_score = $max_score = 0; |
|
125
|
|
|
|
|
126
|
|
|
$remainingMessage = ''; |
|
127
|
|
|
$attemptButton = ''; |
|
128
|
|
|
|
|
129
|
|
|
if ($origin !== 'embeddable') { |
|
130
|
|
|
$attemptButton = Display::toolbarButton( |
|
131
|
|
|
get_lang('AnotherAttempt'), |
|
132
|
|
|
api_get_path(WEB_CODE_PATH).'exercise/overview.php?'.api_get_cidreq().'&'.http_build_query([ |
|
133
|
|
|
'exerciseId' => $objExercise->id, |
|
134
|
|
|
'learnpath_id' => $learnpath_id, |
|
135
|
|
|
'learnpath_item_id' => $learnpath_item_id, |
|
136
|
|
|
'learnpath_item_view_id' => $learnpath_item_view_id, |
|
137
|
|
|
]), |
|
138
|
|
|
'pencil-square-o', |
|
139
|
|
|
'info' |
|
140
|
|
|
); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
// We check if the user attempts before sending to the exercise_result.php |
|
144
|
|
|
if ($objExercise->selectAttempts() > 0) { |
|
145
|
|
|
$attempt_count = Event::get_attempt_count( |
|
146
|
|
|
api_get_user_id(), |
|
147
|
|
|
$objExercise->id, |
|
148
|
|
|
$learnpath_id, |
|
149
|
|
|
$learnpath_item_id, |
|
150
|
|
|
$learnpath_item_view_id |
|
151
|
|
|
); |
|
152
|
|
|
if ($attempt_count >= $objExercise->selectAttempts()) { |
|
153
|
|
|
echo Display::return_message( |
|
154
|
|
|
sprintf(get_lang('ReachedMaxAttempts'), $objExercise->selectTitle(), $objExercise->selectAttempts()), |
|
155
|
|
|
'warning', |
|
156
|
|
|
false |
|
157
|
|
|
); |
|
158
|
|
|
if (!in_array($origin, ['learnpath', 'embeddable'])) { |
|
159
|
|
|
//we are not in learnpath tool |
|
160
|
|
|
Display::display_footer(); |
|
161
|
|
|
} |
|
162
|
|
|
exit; |
|
163
|
|
|
} else { |
|
164
|
|
|
$attempt_count++; |
|
165
|
|
|
$remainingAttempts = $objExercise->selectAttempts() - $attempt_count; |
|
166
|
|
|
|
|
167
|
|
|
if ($remainingAttempts) { |
|
168
|
|
|
$attemptMessage = sprintf(get_lang('RemainingXAttempts'), $remainingAttempts); |
|
169
|
|
|
$remainingMessage = sprintf("<p>%s</p> %s", $attemptMessage, $attemptButton); |
|
170
|
|
|
} |
|
171
|
|
|
} |
|
172
|
|
|
} else { |
|
173
|
|
|
$remainingMessage = $attemptButton ? "<p>$attemptButton</p>" : ''; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
$total_score = 0; |
|
177
|
|
|
if (!empty($exercise_stat_info)) { |
|
178
|
|
|
$total_score = $exercise_stat_info['score']; |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
$max_score = $objExercise->get_max_score(); |
|
182
|
|
|
|
|
183
|
|
|
if ($origin !== 'embeddable') { |
|
184
|
|
|
echo Display::return_message(get_lang('Saved').'<br />', 'normal', false); |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
|
|
if ($origin == 'embeddable') { |
|
188
|
|
|
showEmbeddableFinishButton(); |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
// Display and save questions |
|
192
|
|
|
ExerciseLib::displayQuestionListByAttempt( |
|
193
|
|
|
$objExercise, |
|
194
|
|
|
$exe_id, |
|
195
|
|
|
true, |
|
196
|
|
|
$remainingMessage |
|
197
|
|
|
); |
|
198
|
|
|
|
|
199
|
|
|
//Unset session for clock time |
|
200
|
|
|
ExerciseLib::exercise_time_control_delete( |
|
201
|
|
|
$objExercise->id, |
|
202
|
|
|
$learnpath_id, |
|
203
|
|
|
$learnpath_item_id |
|
204
|
|
|
); |
|
205
|
|
|
|
|
206
|
|
|
ExerciseLib::delete_chat_exercise_session($exe_id); |
|
207
|
|
|
|
|
208
|
|
|
if (!in_array($origin, ['learnpath', 'embeddable'])) { |
|
209
|
|
|
echo '<div class="question-return">'; |
|
210
|
|
|
echo Display::url( |
|
211
|
|
|
get_lang('ReturnToCourseHomepage'), |
|
212
|
|
|
api_get_course_url(), |
|
213
|
|
|
['class' => 'btn btn-primary'] |
|
214
|
|
|
); |
|
215
|
|
|
echo '</div>'; |
|
216
|
|
|
|
|
217
|
|
|
if (api_is_allowed_to_session_edit()) { |
|
218
|
|
|
Session::erase('objExercise'); |
|
219
|
|
|
Session::erase('exe_id'); |
|
220
|
|
|
Session::erase('calculatedAnswerId'); |
|
221
|
|
|
Session::erase('duration_time_previous'); |
|
222
|
|
|
Session::erase('duration_time'); |
|
223
|
|
|
} |
|
224
|
|
|
Display::display_footer(); |
|
225
|
|
|
} elseif ($origin == 'embeddable') { |
|
226
|
|
|
if (api_is_allowed_to_session_edit()) { |
|
227
|
|
|
Session::erase('objExercise'); |
|
228
|
|
|
Session::erase('exe_id'); |
|
229
|
|
|
Session::erase('calculatedAnswerId'); |
|
230
|
|
|
Session::erase('duration_time_previous'); |
|
231
|
|
|
Session::erase('duration_time'); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
Session::write('attempt_remaining', $remainingMessage); |
|
235
|
|
|
|
|
236
|
|
|
showEmbeddableFinishButton(); |
|
237
|
|
|
|
|
238
|
|
|
Display::display_reduced_footer(); |
|
239
|
|
|
} else { |
|
240
|
|
|
$lp_mode = Session::read('lp_mode'); |
|
241
|
|
|
$url = '../lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$learnpath_id.'&lp_item_id='.$learnpath_item_id.'&exeId='.$exercise_stat_info['exe_id'].'&fb_type='.$objExercise->feedback_type.'#atoc_'.$learnpath_item_id; |
|
242
|
|
|
$href = $lp_mode == 'fullscreen' ? ' window.opener.location.href="'.$url.'" ' : ' top.location.href="'.$url.'"'; |
|
243
|
|
|
|
|
244
|
|
|
if (api_is_allowed_to_session_edit()) { |
|
245
|
|
|
Session::erase('objExercise'); |
|
246
|
|
|
Session::erase('exe_id'); |
|
247
|
|
|
Session::erase('calculatedAnswerId'); |
|
248
|
|
|
Session::erase('duration_time_previous'); |
|
249
|
|
|
Session::erase('duration_time'); |
|
250
|
|
|
} |
|
251
|
|
|
Session::write('attempt_remaining', $remainingMessage); |
|
252
|
|
|
|
|
253
|
|
|
// Record the results in the learning path, using the SCORM interface (API) |
|
254
|
|
|
echo "<script>window.parent.API.void_save_asset('$total_score', '$max_score', 0, 'completed');</script>"; |
|
255
|
|
|
echo '<script type="text/javascript">'.$href.'</script>'; |
|
256
|
|
|
|
|
257
|
|
|
Display::display_reduced_footer(); |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
function showEmbeddableFinishButton() |
|
261
|
|
|
{ |
|
262
|
|
|
echo '<script> |
|
263
|
|
|
$(function () { |
|
264
|
|
|
$(\'.btn-close-quiz\').on(\'click\', function () { |
|
265
|
|
|
window.parent.$(\'video:not(.skip), audio:not(.skip)\').get(0).play(); |
|
266
|
|
|
}); |
|
267
|
|
|
}); |
|
268
|
|
|
</script>'; |
|
269
|
|
|
|
|
270
|
|
|
echo Display::tag( |
|
271
|
|
|
'p', |
|
272
|
|
|
Display::toolbarButton( |
|
273
|
|
|
get_lang('EndTest'), |
|
274
|
|
|
'#', |
|
275
|
|
|
'times', |
|
276
|
|
|
'warning', |
|
277
|
|
|
['role' => 'button', 'class' => 'btn-close-quiz'] |
|
278
|
|
|
), |
|
279
|
|
|
['class' => 'text-right'] |
|
280
|
|
|
); |
|
281
|
|
|
} |
|
282
|
|
|
|