9fcf51d9 |
1 | <?php // $Id$ |
5491947a |
2 | /** |
3 | * Local library file for Lesson. These are non-standard functions that are used |
4 | * only by Lesson. |
5 | * |
6 | * @version $Id$ |
7 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
8 | * @package lesson |
9 | **/ |
4b55d2af |
10 | |
11 | /** |
12 | * Next page -> any page not seen before |
13 | */ |
5e7856af |
14 | if (!defined("LESSON_UNSEENPAGE")) { |
ac8e16be |
15 | define("LESSON_UNSEENPAGE", 1); // Next page -> any page not seen before |
4b55d2af |
16 | } |
17 | /** |
18 | * Next page -> any page not answered correctly |
19 | */ |
5e7856af |
20 | if (!defined("LESSON_UNANSWEREDPAGE")) { |
ac8e16be |
21 | define("LESSON_UNANSWEREDPAGE", 2); // Next page -> any page not answered correctly |
4b55d2af |
22 | } |
5e7856af |
23 | |
4b55d2af |
24 | /** |
25 | * Define different lesson flows for next page |
26 | */ |
5e7856af |
27 | $LESSON_NEXTPAGE_ACTION = array (0 => get_string("normal", "lesson"), |
28 | LESSON_UNSEENPAGE => get_string("showanunseenpage", "lesson"), |
29 | LESSON_UNANSWEREDPAGE => get_string("showanunansweredpage", "lesson") ); |
30 | |
4b55d2af |
31 | // Lesson jump types defined |
32 | // TODO: instead of using define statements, create an array with all the jump values |
5e7856af |
33 | |
4b55d2af |
34 | /** |
35 | * Jump to Next Page |
36 | */ |
5e7856af |
37 | if (!defined("LESSON_NEXTPAGE")) { |
4b55d2af |
38 | define("LESSON_NEXTPAGE", -1); |
39 | } |
40 | /** |
41 | * End of Lesson |
42 | */ |
5e7856af |
43 | if (!defined("LESSON_EOL")) { |
4b55d2af |
44 | define("LESSON_EOL", -9); |
45 | } |
46 | /** |
47 | * Jump to an unseen page within a branch and end of branch or end of lesson |
48 | */ |
5e7856af |
49 | if (!defined("LESSON_UNSEENBRANCHPAGE")) { |
4b55d2af |
50 | define("LESSON_UNSEENBRANCHPAGE", -50); |
51 | } |
52 | /** |
53 | * Jump to Previous Page |
54 | */ |
5e7856af |
55 | if (!defined("LESSON_PREVIOUSPAGE")) { |
4b55d2af |
56 | define("LESSON_PREVIOUSPAGE", -40); |
57 | } |
58 | /** |
59 | * Jump to a random page within a branch and end of branch or end of lesson |
60 | */ |
5e7856af |
61 | if (!defined("LESSON_RANDOMPAGE")) { |
4b55d2af |
62 | define("LESSON_RANDOMPAGE", -60); |
63 | } |
64 | /** |
65 | * Jump to a random Branch |
66 | */ |
5e7856af |
67 | if (!defined("LESSON_RANDOMBRANCH")) { |
4b55d2af |
68 | define("LESSON_RANDOMBRANCH", -70); |
69 | } |
70 | /** |
71 | * Cluster Jump |
72 | */ |
5e7856af |
73 | if (!defined("LESSON_CLUSTERJUMP")) { |
4b55d2af |
74 | define("LESSON_CLUSTERJUMP", -80); |
75 | } |
76 | /** |
77 | * Undefined |
78 | */ |
5e7856af |
79 | if (!defined("LESSON_UNDEFINED")) { |
4b55d2af |
80 | define("LESSON_UNDEFINED", -99); |
81 | } |
82 | |
83 | // Lesson question types defined |
5e7856af |
84 | |
4b55d2af |
85 | /** |
86 | * Short answer question type |
87 | */ |
5e7856af |
88 | if (!defined("LESSON_SHORTANSWER")) { |
89 | define("LESSON_SHORTANSWER", "1"); |
90 | } |
4b55d2af |
91 | /** |
92 | * True/False question type |
93 | */ |
5e7856af |
94 | if (!defined("LESSON_TRUEFALSE")) { |
95 | define("LESSON_TRUEFALSE", "2"); |
96 | } |
4b55d2af |
97 | /** |
98 | * Multichoice question type |
99 | * |
100 | * If you change the value of this then you need |
101 | * to change it in restorelib.php as well. |
102 | */ |
103 | if (!defined("LESSON_MULTICHOICE")) { |
5e7856af |
104 | define("LESSON_MULTICHOICE", "3"); |
105 | } |
4b55d2af |
106 | /** |
107 | * Random question type - not used |
108 | */ |
5e7856af |
109 | if (!defined("LESSON_RANDOM")) { |
110 | define("LESSON_RANDOM", "4"); |
111 | } |
4b55d2af |
112 | /** |
113 | * Matching question type |
114 | * |
115 | * If you change the value of this then you need |
116 | * to change it in restorelib.php, in mysql.php |
117 | * and postgres7.php as well. |
118 | */ |
119 | if (!defined("LESSON_MATCHING")) { |
b9869082 |
120 | define("LESSON_MATCHING", "5"); |
5e7856af |
121 | } |
4b55d2af |
122 | /** |
123 | * Not sure - not used |
124 | */ |
5e7856af |
125 | if (!defined("LESSON_RANDOMSAMATCH")) { |
126 | define("LESSON_RANDOMSAMATCH", "6"); |
127 | } |
4b55d2af |
128 | /** |
129 | * Not sure - not used |
130 | */ |
5e7856af |
131 | if (!defined("LESSON_DESCRIPTION")) { |
132 | define("LESSON_DESCRIPTION", "7"); |
133 | } |
4b55d2af |
134 | /** |
135 | * Numerical question type |
136 | */ |
5e7856af |
137 | if (!defined("LESSON_NUMERICAL")) { |
138 | define("LESSON_NUMERICAL", "8"); |
139 | } |
4b55d2af |
140 | /** |
141 | * Multichoice with multianswer question type |
142 | */ |
5e7856af |
143 | if (!defined("LESSON_MULTIANSWER")) { |
144 | define("LESSON_MULTIANSWER", "9"); |
145 | } |
4b55d2af |
146 | /** |
147 | * Essay question type |
148 | */ |
5e7856af |
149 | if (!defined("LESSON_ESSAY")) { |
ac8e16be |
150 | define("LESSON_ESSAY", "10"); |
5e7856af |
151 | } |
5e7856af |
152 | |
4b55d2af |
153 | /** |
154 | * Lesson question type array. |
155 | * Contains all question types used |
156 | */ |
5e7856af |
157 | $LESSON_QUESTION_TYPE = array ( LESSON_MULTICHOICE => get_string("multichoice", "quiz"), |
158 | LESSON_TRUEFALSE => get_string("truefalse", "quiz"), |
159 | LESSON_SHORTANSWER => get_string("shortanswer", "quiz"), |
160 | LESSON_NUMERICAL => get_string("numerical", "quiz"), |
161 | LESSON_MATCHING => get_string("match", "quiz"), |
62eda6ea |
162 | LESSON_ESSAY => get_string("essay", "lesson") |
5e7856af |
163 | // LESSON_DESCRIPTION => get_string("description", "quiz"), |
164 | // LESSON_RANDOM => get_string("random", "quiz"), |
165 | // LESSON_RANDOMSAMATCH => get_string("randomsamatch", "quiz"), |
166 | // LESSON_MULTIANSWER => get_string("multianswer", "quiz"), |
167 | ); |
168 | |
4b55d2af |
169 | // Non-question page types |
170 | |
171 | /** |
172 | * Branch Table page |
173 | */ |
5e7856af |
174 | if (!defined("LESSON_BRANCHTABLE")) { |
175 | define("LESSON_BRANCHTABLE", "20"); |
176 | } |
4b55d2af |
177 | /** |
178 | * End of Branch page |
179 | */ |
5e7856af |
180 | if (!defined("LESSON_ENDOFBRANCH")) { |
181 | define("LESSON_ENDOFBRANCH", "21"); |
182 | } |
4b55d2af |
183 | /** |
184 | * Start of Cluster page |
185 | */ |
186 | if (!defined("LESSON_CLUSTER")) { |
187 | define("LESSON_CLUSTER", "30"); |
188 | } |
189 | /** |
190 | * End of Cluster page |
191 | */ |
192 | if (!defined("LESSON_ENDOFCLUSTER")) { |
193 | define("LESSON_ENDOFCLUSTER", "31"); |
194 | } |
195 | |
196 | // other variables... |
5e7856af |
197 | |
4b55d2af |
198 | /** |
199 | * Flag for the editor for the answer textarea. |
200 | */ |
5e7856af |
201 | if (!defined("LESSON_ANSWER_EDITOR")) { |
202 | define("LESSON_ANSWER_EDITOR", "1"); |
203 | } |
4b55d2af |
204 | /** |
205 | * Flag for the editor for the response textarea. |
206 | */ |
5e7856af |
207 | if (!defined("LESSON_RESPONSE_EDITOR")) { |
208 | define("LESSON_RESPONSE_EDITOR", "2"); |
209 | } |
210 | |
211 | ////////////////////////////////////////////////////////////////////////////////////// |
212 | /// Any other lesson functions go here. Each of them must have a name that |
213 | /// starts with lesson_ |
214 | |
9fcf51d9 |
215 | /** |
216 | * Print the standard header for lesson module |
217 | * |
40d6de1a |
218 | * This will also print up to three |
219 | * buttons in the breadcrumb, lesson heading |
220 | * lesson tabs, lesson notifications and perhaps |
221 | * a popup with a media file. |
222 | * |
9fcf51d9 |
223 | * @param object $cm Course module record object |
40d6de1a |
224 | * @param object $course Course record object |
225 | * @param object $lesson Lesson record object |
9fcf51d9 |
226 | * @param string $currenttab Current tab for the lesson tabs |
40d6de1a |
227 | * @param boolean $extraeditbuttons Show the extra edit buttons next to the 'Update this lesson' button. |
228 | * @param integer $lessonpageid if $extraeditbuttons is true then you must pass the page id here. |
9fcf51d9 |
229 | **/ |
40d6de1a |
230 | function lesson_print_header($cm, $course, $lesson, $currenttab = '', $extraeditbuttons = false, $lessonpageid = NULL) { |
231 | global $CFG, $PAGE; |
888f0c54 |
232 | |
40d6de1a |
233 | // Note: MDL-19010 there will be further changes to printing header and blocks. |
234 | // The code will be much nicer than this eventually. |
235 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
236 | $activityname = format_string($lesson->name, true, $course->id); |
41d50337 |
237 | $strlesson = get_string('modulename', 'lesson'); |
888f0c54 |
238 | |
40d6de1a |
239 | if (empty($title)) { |
240 | $title = "{$course->shortname}: $activityname"; |
241 | } |
888f0c54 |
242 | |
40d6de1a |
243 | /// Build the buttons |
fb992d71 |
244 | if (has_capability('mod/lesson:edit', $context)) { |
40d6de1a |
245 | $buttons = update_module_button($cm->id, $course->id, $strlesson); |
246 | if ($extraeditbuttons) { |
247 | if ($lessonpageid === NULL) { |
248 | print_error('invalidpageid', 'lesson'); |
249 | } |
250 | if (!empty($lessonpageid) and $lessonpageid != LESSON_EOL) { |
251 | $buttons .= '<form '.$CFG->frametarget.' method="get" action="'.$CFG->wwwroot.'/mod/lesson/lesson.php">'. |
252 | '<input type="hidden" name="id" value="'.$cm->id.'" />'. |
253 | '<input type="hidden" name="action" value="editpage" />'. |
254 | '<input type="hidden" name="redirect" value="navigation" />'. |
255 | '<input type="hidden" name="pageid" value="'.$lessonpageid.'" />'. |
256 | '<input type="submit" value="'.get_string('editpagecontent', 'lesson').'" />'. |
257 | '</form>'; |
258 | |
259 | if (!empty($CFG->showblocksonmodpages) and $PAGE->user_allowed_editing()) { |
260 | if ($PAGE->user_is_editing()) { |
261 | $onoff = 'off'; |
262 | } else { |
263 | $onoff = 'on'; |
264 | } |
265 | $buttons .= '<form '.$CFG->frametarget.' method="get" action="'.$CFG->wwwroot.'/mod/lesson/view.php">'. |
266 | '<input type="hidden" name="id" value="'.$cm->id.'" />'. |
267 | '<input type="hidden" name="pageid" value="'.$lessonpageid.'" />'. |
268 | '<input type="hidden" name="edit" value="'.$onoff.'" />'. |
269 | '<input type="submit" value="'.get_string("blocksedit$onoff").'" /> |
270 | </form>'; |
271 | } |
272 | } |
273 | $buttons = '<span class="edit_buttons">' . $buttons .'</span>'; |
274 | } |
fb992d71 |
275 | } else { |
40d6de1a |
276 | $buttons = ' '; |
fb992d71 |
277 | } |
888f0c54 |
278 | |
9fcf51d9 |
279 | /// Header setup |
40d6de1a |
280 | $navigation = build_navigation(array(), $cm); |
281 | print_header($title, $course->fullname, $navigation, '', '', true, $buttons, navmenu($course, $cm)); |
888f0c54 |
282 | |
0ae3b5d3 |
283 | if (has_capability('mod/lesson:manage', $context)) { |
40d6de1a |
284 | print_heading_with_help($activityname, 'overview', 'lesson'); |
888f0c54 |
285 | |
286 | if (!empty($currenttab)) { |
287 | include($CFG->dirroot.'/mod/lesson/tabs.php'); |
288 | } |
d1b025d0 |
289 | } else { |
40d6de1a |
290 | print_heading($activityname); |
9fcf51d9 |
291 | } |
888f0c54 |
292 | |
f15eb92c |
293 | lesson_print_messages(); |
9fcf51d9 |
294 | } |
295 | |
296 | /** |
297 | * Returns course module, course and module instance given |
298 | * either the course module ID or a lesson module ID. |
299 | * |
300 | * @param int $cmid Course Module ID |
301 | * @param int $lessonid Lesson module instance ID |
302 | * @return array array($cm, $course, $lesson) |
303 | **/ |
304 | function lesson_get_basics($cmid = 0, $lessonid = 0) { |
646fc290 |
305 | global $DB; |
306 | |
9fcf51d9 |
307 | if ($cmid) { |
f15eb92c |
308 | if (!$cm = get_coursemodule_from_id('lesson', $cmid)) { |
86f93345 |
309 | print_error('invalidcoursemodule'); |
9fcf51d9 |
310 | } |
646fc290 |
311 | if (!$course = $DB->get_record('course', array('id' => $cm->course))) { |
86f93345 |
312 | print_error('coursemisconf'); |
9fcf51d9 |
313 | } |
646fc290 |
314 | if (!$lesson = $DB->get_record('lesson', array('id' => $cm->instance))) { |
86f93345 |
315 | print_error('invalidcoursemodule'); |
9fcf51d9 |
316 | } |
317 | } else if ($lessonid) { |
646fc290 |
318 | if (!$lesson = $DB->get_record('lesson', array('id' => $lessonid))) { |
86f93345 |
319 | print_error('invalidcoursemodule'); |
9fcf51d9 |
320 | } |
646fc290 |
321 | if (!$course = $DB->get_record('course', array('id' => $lesson->course))) { |
86f93345 |
322 | print_error('coursemisconf'); |
9fcf51d9 |
323 | } |
324 | if (!$cm = get_coursemodule_from_instance('lesson', $lesson->id, $course->id)) { |
86f93345 |
325 | print_error('invalidcoursemodule'); |
9fcf51d9 |
326 | } |
327 | } else { |
86f93345 |
328 | print_error('invalidid', 'lesson'); |
9fcf51d9 |
329 | } |
330 | |
331 | return array($cm, $course, $lesson); |
332 | } |
333 | |
6e1ff5c8 |
334 | /** |
335 | * Sets a message to be printed. Messages are printed |
336 | * by calling {@link lesson_print_messages()}. |
337 | * |
338 | * @uses $SESSION |
339 | * @param string $message The message to be printed |
340 | * @param string $class Class to be passed to {@link notify()}. Usually notifyproblem or notifysuccess. |
341 | * @param string $align Alignment of the message |
342 | * @return boolean |
343 | **/ |
344 | function lesson_set_message($message, $class="notifyproblem", $align='center') { |
345 | global $SESSION; |
346 | |
347 | if (empty($SESSION->lesson_messages) or !is_array($SESSION->lesson_messages)) { |
348 | $SESSION->lesson_messages = array(); |
349 | } |
350 | |
351 | $SESSION->lesson_messages[] = array($message, $class, $align); |
352 | |
353 | return true; |
354 | } |
355 | |
356 | /** |
357 | * Print all set messages. |
358 | * |
359 | * See {@link lesson_set_message()} for setting messages. |
360 | * |
361 | * Uses {@link notify()} to print the messages. |
362 | * |
363 | * @uses $SESSION |
364 | * @return boolean |
365 | **/ |
366 | function lesson_print_messages() { |
367 | global $SESSION; |
368 | |
369 | if (empty($SESSION->lesson_messages)) { |
370 | // No messages to print |
371 | return true; |
372 | } |
373 | |
374 | foreach($SESSION->lesson_messages as $message) { |
375 | notify($message[0], $message[1], $message[2]); |
376 | } |
377 | |
378 | // Reset |
379 | unset($SESSION->lesson_messages); |
380 | |
381 | return true; |
382 | } |
383 | |
259990d2 |
384 | /** |
385 | * Prints a lesson link that submits a form. |
386 | * |
387 | * If Javascript is disabled, then a regular submit button is printed |
388 | * |
68a1e8fb |
389 | * @param string $name Name of the link or button |
390 | * @param string $form The name of the form to be submitted |
391 | * @param string $align Alignment of the button |
392 | * @param string $class Class names to add to the div wrapper |
393 | * @param string $title Title for the link (Not used if javascript is disabled) |
394 | * @param string $id ID tag |
395 | * @param boolean $return Return flag |
259990d2 |
396 | * @return mixed boolean/html |
397 | **/ |
398 | function lesson_print_submit_link($name, $form, $align = 'center', $class='standardbutton', $title = '', $id = '', $return = false) { |
563106f0 |
399 | if (!empty($align)) { |
4085962a |
400 | $align = " style=\"text-align:$align\""; |
563106f0 |
401 | } |
259990d2 |
402 | if (!empty($id)) { |
403 | $id = " id=\"$id\""; |
404 | } |
405 | if (empty($title)) { |
406 | $title = $name; |
407 | } |
62bb11d8 |
408 | |
4cb35c1b |
409 | $output = "<div class=\"lessonbutton $class\" $align>\n"; |
37aa59a9 |
410 | $output .= "<input type=\"submit\" value=\"$name\" $align $id />"; |
259990d2 |
411 | $output .= "</div>\n"; |
412 | |
2cb24b64 |
413 | if ($return) { |
414 | return $output; |
415 | } else { |
416 | echo $output; |
417 | return true; |
418 | } |
419 | } |
420 | |
421 | /** |
422 | * Prints a time remaining in the following format: H:MM:SS |
423 | * |
424 | * @param int $starttime Time when the lesson started |
425 | * @param int $maxtime Length of the lesson |
426 | * @param boolean $return Return output switch |
427 | * @return mixed boolean/string |
428 | **/ |
2163c226 |
429 | function lesson_print_time_remaining($starttime, $maxtime, $return = false) { |
2cb24b64 |
430 | // Calculate hours, minutes and seconds |
431 | $timeleft = $starttime + $maxtime * 60 - time(); |
432 | $hours = floor($timeleft/3600); |
433 | $timeleft = $timeleft - ($hours * 3600); |
434 | $minutes = floor($timeleft/60); |
435 | $secs = $timeleft - ($minutes * 60); |
436 | |
437 | if ($minutes < 10) { |
438 | $minutes = "0$minutes"; |
439 | } |
440 | if ($secs < 10) { |
441 | $secs = "0$secs"; |
442 | } |
443 | $output = array(); |
444 | $output[] = $hours; |
445 | $output[] = $minutes; |
446 | $output[] = $secs; |
447 | |
448 | $output = implode(':', $output); |
449 | |
259990d2 |
450 | if ($return) { |
451 | return $output; |
452 | } else { |
453 | echo $output; |
454 | return true; |
455 | } |
456 | } |
457 | |
68a1e8fb |
458 | /** |
459 | * Prints the page action buttons |
460 | * |
461 | * Move/Edit/Preview/Delete |
462 | * |
463 | * @uses $CFG |
464 | * @param int $cmid Course Module ID |
260a56b1 |
465 | * @param object $page Page record |
68a1e8fb |
466 | * @param boolean $printmove Flag to print the move button or not |
260a56b1 |
467 | * @param boolean $printaddpage Flag to print the add page drop-down or not |
68a1e8fb |
468 | * @param boolean $return Return flag |
469 | * @return mixed boolean/string |
470 | **/ |
260a56b1 |
471 | function lesson_print_page_actions($cmid, $page, $printmove, $printaddpage = false, $return = false) { |
4096752d |
472 | global $CFG, $OUTPUT; |
40d6de1a |
473 | |
68a1e8fb |
474 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
475 | $actions = array(); |
40d6de1a |
476 | |
68a1e8fb |
477 | if (has_capability('mod/lesson:edit', $context)) { |
478 | if ($printmove) { |
2ba9db3c |
479 | $actions[] = "<a title=\"".get_string('move')."\" href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&action=move&pageid=$page->id\"> |
4096752d |
480 | <img src=\"" . $OUTPUT->old_icon_url('t/move') . "\" class=\"iconsmall\" alt=\"".get_string('move')."\" /></a>\n"; |
68a1e8fb |
481 | } |
260a56b1 |
482 | $actions[] = "<a title=\"".get_string('update')."\" href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&action=editpage&pageid=$page->id\"> |
4096752d |
483 | <img src=\"" . $OUTPUT->old_icon_url('t/edit') . "\" class=\"iconsmall\" alt=\"".get_string('update')."\" /></a>\n"; |
68a1e8fb |
484 | |
260a56b1 |
485 | $actions[] = "<a title=\"".get_string('preview')."\" href=\"$CFG->wwwroot/mod/lesson/view.php?id=$cmid&pageid=$page->id\"> |
4096752d |
486 | <img src=\"" . $OUTPUT->old_icon_url('t/preview') . "\" class=\"iconsmall\" alt=\"".get_string('preview')."\" /></a>\n"; |
40d6de1a |
487 | |
260a56b1 |
488 | $actions[] = "<a title=\"".get_string('delete')."\" href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&sesskey=".sesskey()."&action=confirmdelete&pageid=$page->id\"> |
4096752d |
489 | <img src=\"" . $OUTPUT->old_icon_url('t/delete') . "\" class=\"iconsmall\" alt=\"".get_string('delete')."\" /></a>\n"; |
40d6de1a |
490 | |
260a56b1 |
491 | if ($printaddpage) { |
492 | // Add page drop-down |
493 | $options = array(); |
494 | $options['addcluster&sesskey='.sesskey()] = get_string('clustertitle', 'lesson'); |
495 | $options['addendofcluster&sesskey='.sesskey()] = get_string('endofclustertitle', 'lesson'); |
496 | $options['addbranchtable'] = get_string('branchtable', 'lesson'); |
497 | $options['addendofbranch&sesskey='.sesskey()] = get_string('endofbranch', 'lesson'); |
498 | $options['addpage'] = get_string('question', 'lesson'); |
499 | // Base url |
500 | $common = "$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&pageid=$page->id&action="; |
40d6de1a |
501 | |
260a56b1 |
502 | $actions[] = popup_form($common, $options, "addpage_$page->id", '', get_string('addpage', 'lesson').'...', '', '', true); |
503 | } |
68a1e8fb |
504 | } |
40d6de1a |
505 | |
68a1e8fb |
506 | $actions = implode(' ', $actions); |
40d6de1a |
507 | |
68a1e8fb |
508 | if ($return) { |
509 | return $actions; |
510 | } else { |
511 | echo $actions; |
512 | return false; |
513 | } |
514 | } |
515 | |
516 | /** |
517 | * Prints the add links in expanded view or single view when editing |
518 | * |
519 | * @uses $CFG |
520 | * @param int $cmid Course Module ID |
521 | * @param int $prevpageid Previous page id |
522 | * @param boolean $return Return flag |
523 | * @return mixed boolean/string |
524 | * @todo &pageid does not make sense, it is prevpageid |
525 | **/ |
526 | function lesson_print_add_links($cmid, $prevpageid, $return = false) { |
527 | global $CFG; |
528 | |
529 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
530 | |
531 | $links = ''; |
532 | if (has_capability('mod/lesson:edit', $context)) { |
533 | $links = array(); |
534 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/import.php?id=$cmid&pageid=$prevpageid\">". |
535 | get_string('importquestions', 'lesson').'</a>'; |
536 | |
537 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&sesskey=".sesskey()."&action=addcluster&pageid=$prevpageid\">". |
538 | get_string('addcluster', 'lesson').'</a>'; |
539 | |
540 | if ($prevpageid != 0) { |
541 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&sesskey=".sesskey()."&action=addendofcluster&pageid=$prevpageid\">". |
542 | get_string('addendofcluster', 'lesson').'</a>'; |
543 | } |
544 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&action=addbranchtable&pageid=$prevpageid\">". |
545 | get_string('addabranchtable', 'lesson').'</a>'; |
546 | |
547 | if ($prevpageid != 0) { |
548 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&sesskey=".sesskey()."&action=addendofbranch&pageid=$prevpageid\">". |
549 | get_string('addanendofbranch', 'lesson').'</a>'; |
550 | } |
551 | |
552 | $links[] = "<a href=\"$CFG->wwwroot/mod/lesson/lesson.php?id=$cmid&action=addpage&pageid=$prevpageid\">". |
553 | get_string('addaquestionpagehere', 'lesson').'</a>'; |
554 | |
555 | $links = implode(" | \n", $links); |
556 | $links = "\n<div class=\"addlinks\">\n$links\n</div>\n"; |
557 | } |
558 | |
559 | if ($return) { |
560 | return $links; |
561 | } else { |
562 | echo $links; |
563 | return true; |
564 | } |
565 | } |
566 | |
567 | /** |
568 | * Returns the string for a page type |
569 | * |
570 | * @uses $LESSON_QUESTION_TYPE |
571 | * @param int $qtype Page type |
572 | * @return string |
573 | **/ |
574 | function lesson_get_qtype_name($qtype) { |
575 | global $LESSON_QUESTION_TYPE; |
576 | switch ($qtype) { |
577 | case LESSON_ESSAY : |
578 | case LESSON_SHORTANSWER : |
579 | case LESSON_MULTICHOICE : |
580 | case LESSON_MATCHING : |
581 | case LESSON_TRUEFALSE : |
582 | case LESSON_NUMERICAL : |
583 | return $LESSON_QUESTION_TYPE[$qtype]; |
584 | break; |
585 | case LESSON_BRANCHTABLE : |
586 | return get_string("branchtable", "lesson"); |
587 | break; |
588 | case LESSON_ENDOFBRANCH : |
589 | return get_string("endofbranch", "lesson"); |
590 | break; |
591 | case LESSON_CLUSTER : |
592 | return get_string("clustertitle", "lesson"); |
593 | break; |
594 | case LESSON_ENDOFCLUSTER : |
595 | return get_string("endofclustertitle", "lesson"); |
596 | break; |
597 | default: |
598 | return ''; |
599 | break; |
600 | } |
601 | } |
602 | |
603 | /** |
604 | * Returns the string for a jump name |
605 | * |
606 | * @param int $jumpto Jump code or page ID |
607 | * @return string |
608 | **/ |
609 | function lesson_get_jump_name($jumpto) { |
646fc290 |
610 | global $DB; |
611 | |
68a1e8fb |
612 | if ($jumpto == 0) { |
613 | $jumptitle = get_string('thispage', 'lesson'); |
614 | } elseif ($jumpto == LESSON_NEXTPAGE) { |
615 | $jumptitle = get_string('nextpage', 'lesson'); |
616 | } elseif ($jumpto == LESSON_EOL) { |
617 | $jumptitle = get_string('endoflesson', 'lesson'); |
618 | } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) { |
619 | $jumptitle = get_string('unseenpageinbranch', 'lesson'); |
620 | } elseif ($jumpto == LESSON_PREVIOUSPAGE) { |
621 | $jumptitle = get_string('previouspage', 'lesson'); |
622 | } elseif ($jumpto == LESSON_RANDOMPAGE) { |
623 | $jumptitle = get_string('randompageinbranch', 'lesson'); |
624 | } elseif ($jumpto == LESSON_RANDOMBRANCH) { |
625 | $jumptitle = get_string('randombranch', 'lesson'); |
626 | } elseif ($jumpto == LESSON_CLUSTERJUMP) { |
627 | $jumptitle = get_string('clusterjump', 'lesson'); |
628 | } else { |
646fc290 |
629 | if (!$jumptitle = $DB->get_field('lesson_pages', 'title', array('id' => $jumpto))) { |
68a1e8fb |
630 | $jumptitle = '<strong>'.get_string('notdefined', 'lesson').'</strong>'; |
631 | } |
632 | } |
633 | |
634 | return format_string($jumptitle,true); |
635 | } |
636 | |
4b55d2af |
637 | /** |
638 | * Given some question info and some data about the the answers |
639 | * this function parses, organises and saves the question |
640 | * |
641 | * This is only used when IMPORTING questions and is only called |
642 | * from format.php |
643 | * Lifted from mod/quiz/lib.php - |
644 | * 1. all reference to oldanswers removed |
645 | * 2. all reference to quiz_multichoice table removed |
646 | * 3. In SHORTANSWER questions usecase is store in the qoption field |
647 | * 4. In NUMERIC questions store the range as two answers |
648 | * 5. TRUEFALSE options are ignored |
649 | * 6. For MULTICHOICE questions with more than one answer the qoption field is true |
650 | * |
651 | * @param opject $question Contains question data like question, type and answers. |
652 | * @return object Returns $result->error or $result->notice. |
653 | **/ |
5e7856af |
654 | function lesson_save_question_options($question) { |
646fc290 |
655 | global $DB; |
5e7856af |
656 | |
657 | $timenow = time(); |
658 | switch ($question->qtype) { |
659 | case LESSON_SHORTANSWER: |
660 | |
661 | $answers = array(); |
662 | $maxfraction = -1; |
663 | |
664 | // Insert all the new answers |
665 | foreach ($question->answer as $key => $dataanswer) { |
666 | if ($dataanswer != "") { |
f7ffb898 |
667 | $answer = new stdClass; |
5e7856af |
668 | $answer->lessonid = $question->lessonid; |
669 | $answer->pageid = $question->id; |
670 | if ($question->fraction[$key] >=0.5) { |
671 | $answer->jumpto = LESSON_NEXTPAGE; |
672 | } |
673 | $answer->timecreated = $timenow; |
674 | $answer->grade = $question->fraction[$key] * 100; |
675 | $answer->answer = $dataanswer; |
c87a341c |
676 | $answer->response = $question->feedback[$key]; |
a8f3a651 |
677 | $answer->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
678 | $answers[] = $answer->id; |
679 | if ($question->fraction[$key] > $maxfraction) { |
680 | $maxfraction = $question->fraction[$key]; |
681 | } |
682 | } |
683 | } |
684 | |
685 | |
686 | /// Perform sanity checks on fractional grades |
687 | if ($maxfraction != 1) { |
688 | $maxfraction = $maxfraction * 100; |
689 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
690 | return $result; |
691 | } |
692 | break; |
693 | |
694 | case LESSON_NUMERICAL: // Note similarities to SHORTANSWER |
695 | |
696 | $answers = array(); |
697 | $maxfraction = -1; |
698 | |
699 | |
700 | // for each answer store the pair of min and max values even if they are the same |
701 | foreach ($question->answer as $key => $dataanswer) { |
702 | if ($dataanswer != "") { |
f7ffb898 |
703 | $answer = new stdClass; |
5e7856af |
704 | $answer->lessonid = $question->lessonid; |
705 | $answer->pageid = $question->id; |
706 | $answer->jumpto = LESSON_NEXTPAGE; |
707 | $answer->timecreated = $timenow; |
708 | $answer->grade = $question->fraction[$key] * 100; |
dd192b26 |
709 | $min = $question->answer[$key] - $question->tolerance[$key]; |
710 | $max = $question->answer[$key] + $question->tolerance[$key]; |
711 | $answer->answer = $min.":".$max; |
712 | // $answer->answer = $question->min[$key].":".$question->max[$key]; original line for min/max |
5e7856af |
713 | $answer->response = $question->feedback[$key]; |
a8f3a651 |
714 | $answer->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
715 | |
716 | $answers[] = $answer->id; |
717 | if ($question->fraction[$key] > $maxfraction) { |
718 | $maxfraction = $question->fraction[$key]; |
719 | } |
720 | } |
721 | } |
722 | |
723 | /// Perform sanity checks on fractional grades |
724 | if ($maxfraction != 1) { |
725 | $maxfraction = $maxfraction * 100; |
726 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
727 | return $result; |
728 | } |
729 | break; |
730 | |
731 | |
732 | case LESSON_TRUEFALSE: |
733 | |
734 | // the truth |
735 | $answer->lessonid = $question->lessonid; |
736 | $answer->pageid = $question->id; |
737 | $answer->timecreated = $timenow; |
738 | $answer->answer = get_string("true", "quiz"); |
739 | $answer->grade = $question->answer * 100; |
740 | if ($answer->grade > 50 ) { |
741 | $answer->jumpto = LESSON_NEXTPAGE; |
742 | } |
743 | if (isset($question->feedbacktrue)) { |
744 | $answer->response = $question->feedbacktrue; |
745 | } |
a8f3a651 |
746 | $true->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
747 | |
748 | // the lie |
f7ffb898 |
749 | $answer = new stdClass; |
5e7856af |
750 | $answer->lessonid = $question->lessonid; |
751 | $answer->pageid = $question->id; |
752 | $answer->timecreated = $timenow; |
753 | $answer->answer = get_string("false", "quiz"); |
754 | $answer->grade = (1 - (int)$question->answer) * 100; |
755 | if ($answer->grade > 50 ) { |
756 | $answer->jumpto = LESSON_NEXTPAGE; |
757 | } |
758 | if (isset($question->feedbackfalse)) { |
759 | $answer->response = $question->feedbackfalse; |
760 | } |
a8f3a651 |
761 | $false->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
762 | |
763 | break; |
764 | |
765 | |
766 | case LESSON_MULTICHOICE: |
767 | |
768 | $totalfraction = 0; |
769 | $maxfraction = -1; |
770 | |
771 | $answers = array(); |
772 | |
773 | // Insert all the new answers |
774 | foreach ($question->answer as $key => $dataanswer) { |
775 | if ($dataanswer != "") { |
f7ffb898 |
776 | $answer = new stdClass; |
5e7856af |
777 | $answer->lessonid = $question->lessonid; |
778 | $answer->pageid = $question->id; |
779 | $answer->timecreated = $timenow; |
780 | $answer->grade = $question->fraction[$key] * 100; |
62eda6ea |
781 | // changed some defaults |
ac8e16be |
782 | /* Original Code |
783 | if ($answer->grade > 50 ) { |
5e7856af |
784 | $answer->jumpto = LESSON_NEXTPAGE; |
785 | } |
ac8e16be |
786 | Replaced with: */ |
787 | if ($answer->grade > 50 ) { |
788 | $answer->jumpto = LESSON_NEXTPAGE; |
5e7856af |
789 | $answer->score = 1; |
790 | } |
ac8e16be |
791 | // end Replace |
5e7856af |
792 | $answer->answer = $dataanswer; |
793 | $answer->response = $question->feedback[$key]; |
a8f3a651 |
794 | $answer->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
795 | // for Sanity checks |
796 | if ($question->fraction[$key] > 0) { |
797 | $totalfraction += $question->fraction[$key]; |
798 | } |
799 | if ($question->fraction[$key] > $maxfraction) { |
800 | $maxfraction = $question->fraction[$key]; |
801 | } |
802 | } |
803 | } |
804 | |
805 | /// Perform sanity checks on fractional grades |
806 | if ($question->single) { |
807 | if ($maxfraction != 1) { |
808 | $maxfraction = $maxfraction * 100; |
809 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
810 | return $result; |
811 | } |
812 | } else { |
813 | $totalfraction = round($totalfraction,2); |
814 | if ($totalfraction != 1) { |
815 | $totalfraction = $totalfraction * 100; |
816 | $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction); |
817 | return $result; |
818 | } |
819 | } |
820 | break; |
821 | |
822 | case LESSON_MATCHING: |
823 | |
824 | $subquestions = array(); |
825 | |
826 | $i = 0; |
827 | // Insert all the new question+answer pairs |
828 | foreach ($question->subquestions as $key => $questiontext) { |
90455bb3 |
829 | $answertext = $question->subanswers[$key]; |
5e7856af |
830 | if (!empty($questiontext) and !empty($answertext)) { |
f7ffb898 |
831 | $answer = new stdClass; |
5e7856af |
832 | $answer->lessonid = $question->lessonid; |
833 | $answer->pageid = $question->id; |
834 | $answer->timecreated = $timenow; |
835 | $answer->answer = $questiontext; |
836 | $answer->response = $answertext; |
837 | if ($i == 0) { |
838 | // first answer contains the correct answer jump |
839 | $answer->jumpto = LESSON_NEXTPAGE; |
840 | } |
a8f3a651 |
841 | $subquestion->id = $DB->insert_record("lesson_answers", $answer); |
5e7856af |
842 | $subquestions[] = $subquestion->id; |
843 | $i++; |
844 | } |
845 | } |
846 | |
847 | if (count($subquestions) < 3) { |
848 | $result->notice = get_string("notenoughsubquestions", "quiz"); |
849 | return $result; |
850 | } |
851 | |
852 | break; |
853 | |
854 | |
855 | case LESSON_RANDOMSAMATCH: |
856 | $options->question = $question->id; |
857 | $options->choose = $question->choose; |
646fc290 |
858 | if ($existing = $DB->get_record("quiz_randomsamatch", array("question" => $options->question))) { |
5e7856af |
859 | $options->id = $existing->id; |
a8c31db2 |
860 | $DB->update_record("quiz_randomsamatch", $options); |
5e7856af |
861 | } else { |
a8c31db2 |
862 | $DB->insert_record("quiz_randomsamatch", $options); |
5e7856af |
863 | } |
864 | break; |
865 | |
866 | case LESSON_MULTIANSWER: |
646fc290 |
867 | if (!$oldmultianswers = $DB->get_records("quiz_multianswers", array("question" => $question->id), "id ASC")) { |
5e7856af |
868 | $oldmultianswers = array(); |
869 | } |
870 | |
871 | // Insert all the new multi answers |
872 | foreach ($question->answers as $dataanswer) { |
873 | if ($oldmultianswer = array_shift($oldmultianswers)) { // Existing answer, so reuse it |
874 | $multianswer = $oldmultianswer; |
875 | $multianswer->positionkey = $dataanswer->positionkey; |
876 | $multianswer->norm = $dataanswer->norm; |
877 | $multianswer->answertype = $dataanswer->answertype; |
878 | |
879 | if (! $multianswer->answers = quiz_save_multianswer_alternatives |
880 | ($question->id, $dataanswer->answertype, |
881 | $dataanswer->alternatives, $oldmultianswer->answers)) |
882 | { |
883 | $result->error = "Could not update multianswer alternatives! (id=$multianswer->id)"; |
884 | return $result; |
885 | } |
a8c31db2 |
886 | $DB->update_record("quiz_multianswers", $multianswer); |
5e7856af |
887 | } else { // This is a completely new answer |
f7ffb898 |
888 | $multianswer = new stdClass; |
5e7856af |
889 | $multianswer->question = $question->id; |
890 | $multianswer->positionkey = $dataanswer->positionkey; |
891 | $multianswer->norm = $dataanswer->norm; |
892 | $multianswer->answertype = $dataanswer->answertype; |
893 | |
894 | if (! $multianswer->answers = quiz_save_multianswer_alternatives |
895 | ($question->id, $dataanswer->answertype, |
896 | $dataanswer->alternatives)) |
897 | { |
898 | $result->error = "Could not insert multianswer alternatives! (questionid=$question->id)"; |
899 | return $result; |
900 | } |
a8c31db2 |
901 | $DB->insert_record("quiz_multianswers", $multianswer); |
5e7856af |
902 | } |
903 | } |
904 | break; |
905 | |
906 | case LESSON_RANDOM: |
907 | break; |
908 | |
909 | case LESSON_DESCRIPTION: |
910 | break; |
911 | |
912 | default: |
913 | $result->error = "Unsupported question type ($question->qtype)!"; |
914 | return $result; |
915 | break; |
916 | } |
917 | return true; |
918 | } |
4b55d2af |
919 | |
4b55d2af |
920 | /** |
921 | * Determins if a jumpto value is correct or not. |
922 | * |
923 | * returns true if jumpto page is (logically) after the pageid page or |
924 | * if the jumpto value is a special value. Returns false in all other cases. |
925 | * |
926 | * @param int $pageid Id of the page from which you are jumping from. |
927 | * @param int $jumpto The jumpto number. |
928 | * @return boolean True or false after a series of tests. |
4b55d2af |
929 | **/ |
5e7856af |
930 | function lesson_iscorrect($pageid, $jumpto) { |
646fc290 |
931 | global $DB; |
5e7856af |
932 | |
933 | // first test the special values |
934 | if (!$jumpto) { |
935 | // same page |
936 | return false; |
937 | } elseif ($jumpto == LESSON_NEXTPAGE) { |
938 | return true; |
ac8e16be |
939 | } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) { |
5e7856af |
940 | return true; |
941 | } elseif ($jumpto == LESSON_RANDOMPAGE) { |
942 | return true; |
943 | } elseif ($jumpto == LESSON_CLUSTERJUMP) { |
944 | return true; |
5e7856af |
945 | } elseif ($jumpto == LESSON_EOL) { |
946 | return true; |
947 | } |
948 | // we have to run through the pages from pageid looking for jumpid |
646fc290 |
949 | if ($lessonid = $DB->get_field('lesson_pages', 'lessonid', array('id' => $pageid))) { |
950 | if ($pages = $DB->get_records('lesson_pages', array('lessonid' => $lessonid), '', 'id, nextpageid')) { |
f521f98a |
951 | $apageid = $pages[$pageid]->nextpageid; |
952 | while ($apageid != 0) { |
953 | if ($jumpto == $apageid) { |
954 | return true; |
955 | } |
956 | $apageid = $pages[$apageid]->nextpageid; |
957 | } |
5e7856af |
958 | } |
959 | } |
f521f98a |
960 | return false; |
5e7856af |
961 | } |
962 | |
4b55d2af |
963 | /** |
964 | * Checks to see if a page is a branch table or is |
965 | * a page that is enclosed by a branch table and an end of branch or end of lesson. |
966 | * May call this function: {@link lesson_is_page_in_branch()} |
967 | * |
f521f98a |
968 | * @param int $lesson Id of the lesson to which the page belongs. |
4b55d2af |
969 | * @param int $pageid Id of the page. |
970 | * @return boolean True or false. |
4b55d2af |
971 | **/ |
f521f98a |
972 | function lesson_display_branch_jumps($lessonid, $pageid) { |
646fc290 |
973 | global $DB; |
974 | |
ac8e16be |
975 | if($pageid == 0) { |
976 | // first page |
977 | return false; |
978 | } |
979 | // get all of the lesson pages |
646fc290 |
980 | $params = array ("lessonid" => $lessonid); |
981 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
ac8e16be |
982 | // adding first page |
983 | return false; |
984 | } |
985 | |
986 | if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) { |
987 | return true; |
988 | } |
989 | |
990 | return lesson_is_page_in_branch($lessonpages, $pageid); |
5e7856af |
991 | } |
992 | |
4b55d2af |
993 | /** |
994 | * Checks to see if a page is a cluster page or is |
995 | * a page that is enclosed by a cluster page and an end of cluster or end of lesson |
996 | * May call this function: {@link lesson_is_page_in_cluster()} |
997 | * |
f521f98a |
998 | * @param int $lesson Id of the lesson to which the page belongs. |
4b55d2af |
999 | * @param int $pageid Id of the page. |
1000 | * @return boolean True or false. |
4b55d2af |
1001 | **/ |
f521f98a |
1002 | function lesson_display_cluster_jump($lesson, $pageid) { |
646fc290 |
1003 | global $DB; |
1004 | |
ac8e16be |
1005 | if($pageid == 0) { |
1006 | // first page |
1007 | return false; |
1008 | } |
1009 | // get all of the lesson pages |
646fc290 |
1010 | $params = array ("lessonid" => $lesson); |
1011 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
ac8e16be |
1012 | // adding first page |
1013 | return false; |
1014 | } |
1015 | |
1016 | if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) { |
1017 | return true; |
1018 | } |
1019 | |
1020 | return lesson_is_page_in_cluster($lessonpages, $pageid); |
5e7856af |
1021 | |
1022 | } |
1023 | |
4b55d2af |
1024 | /** |
1025 | * Checks to see if a LESSON_CLUSTERJUMP or |
1026 | * a LESSON_UNSEENBRANCHPAGE is used in a lesson. |
1027 | * |
1028 | * This function is only executed when a teacher is |
1029 | * checking the navigation for a lesson. |
1030 | * |
06469639 |
1031 | * @param int $lesson Id of the lesson that is to be checked. |
4b55d2af |
1032 | * @return boolean True or false. |
1033 | **/ |
06469639 |
1034 | function lesson_display_teacher_warning($lesson) { |
646fc290 |
1035 | global $DB; |
1036 | |
ac8e16be |
1037 | // get all of the lesson answers |
646fc290 |
1038 | $params = array ("lessonid" => $lesson); |
1039 | if (!$lessonanswers = $DB->get_records_select("lesson_answers", "lessonid = :lessonid", $params)) { |
ac8e16be |
1040 | // no answers, then not useing cluster or unseen |
1041 | return false; |
1042 | } |
1043 | // just check for the first one that fulfills the requirements |
1044 | foreach ($lessonanswers as $lessonanswer) { |
1045 | if ($lessonanswer->jumpto == LESSON_CLUSTERJUMP || $lessonanswer->jumpto == LESSON_UNSEENBRANCHPAGE) { |
1046 | return true; |
1047 | } |
1048 | } |
1049 | |
1050 | // if no answers use either of the two jumps |
1051 | return false; |
5e7856af |
1052 | } |
1053 | |
1054 | |
4b55d2af |
1055 | /** |
1056 | * Interprets LESSON_CLUSTERJUMP jumpto value. |
1057 | * |
1058 | * This will select a page randomly |
1059 | * and the page selected will be inbetween a cluster page and end of cluter or end of lesson |
1060 | * and the page selected will be a page that has not been viewed already |
1061 | * and if any pages are within a branch table or end of branch then only 1 page within |
1062 | * the branch table or end of branch will be randomly selected (sub clustering). |
1063 | * |
f521f98a |
1064 | * @param int $lessonid Id of the lesson. |
1065 | * @param int $userid Id of the user. |
4b55d2af |
1066 | * @param int $pageid Id of the current page from which we are jumping from. |
1067 | * @return int The id of the next page. |
4b55d2af |
1068 | **/ |
f521f98a |
1069 | function lesson_cluster_jump($lessonid, $userid, $pageid) { |
646fc290 |
1070 | global $DB; |
1071 | |
ac8e16be |
1072 | // get the number of retakes |
318e3745 |
1073 | if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lessonid, "userid"=>$userid))) { |
ac8e16be |
1074 | $retakes = 0; |
1075 | } |
1076 | |
1077 | // get all the lesson_attempts aka what the user has seen |
646fc290 |
1078 | $params = array ("lessonid" => $lessonid, "userid" => $userid, "retry" => $retakes); |
1079 | if ($seen = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params, "timeseen DESC")) { |
ac8e16be |
1080 | foreach ($seen as $value) { // load it into an array that I can more easily use |
1081 | $seenpages[$value->pageid] = $value->pageid; |
1082 | } |
1083 | } else { |
1084 | $seenpages = array(); |
1085 | } |
1086 | |
1087 | // get the lesson pages |
e57bc529 |
1088 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
86f93345 |
1089 | print_error('cannotfindrecords', 'lesson'); |
ac8e16be |
1090 | } |
1091 | // find the start of the cluster |
1092 | while ($pageid != 0) { // this condition should not be satisfied... should be a cluster page |
1093 | if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) { |
1094 | break; |
1095 | } |
1096 | $pageid = $lessonpages[$pageid]->prevpageid; |
1097 | } |
1098 | |
1099 | $pageid = $lessonpages[$pageid]->nextpageid; // move down from the cluster page |
1100 | |
1101 | $clusterpages = array(); |
1102 | while (true) { // now load all the pages into the cluster that are not already inside of a branch table. |
1103 | if ($lessonpages[$pageid]->qtype == LESSON_ENDOFCLUSTER) { |
1104 | // store the endofcluster page's jump |
646fc290 |
1105 | $exitjump = $DB->get_field("lesson_answers", "jumpto", array("pageid" => $pageid, "lessonid" => $lessonid)); |
ac8e16be |
1106 | if ($exitjump == LESSON_NEXTPAGE) { |
1107 | $exitjump = $lessonpages[$pageid]->nextpageid; |
1108 | } |
1109 | if ($exitjump == 0) { |
1110 | $exitjump = LESSON_EOL; |
1111 | } |
1112 | break; |
1113 | } elseif (!lesson_is_page_in_branch($lessonpages, $pageid) && $lessonpages[$pageid]->qtype != LESSON_ENDOFBRANCH) { |
1114 | // load page into array when it is not in a branch table and when it is not an endofbranch |
1115 | $clusterpages[] = $lessonpages[$pageid]; |
1116 | } |
1117 | if ($lessonpages[$pageid]->nextpageid == 0) { |
1118 | // shouldn't ever get here... should be using endofcluster |
1119 | $exitjump = LESSON_EOL; |
1120 | break; |
1121 | } else { |
1122 | $pageid = $lessonpages[$pageid]->nextpageid; |
1123 | } |
1124 | } |
1125 | |
1126 | // filter out the ones we have seen |
1127 | $unseen = array(); |
1128 | foreach ($clusterpages as $clusterpage) { |
1129 | if ($clusterpage->qtype == LESSON_BRANCHTABLE) { // if branchtable, check to see if any pages inside have been viewed |
1130 | $branchpages = lesson_pages_in_branch($lessonpages, $clusterpage->id); // get the pages in the branchtable |
1131 | $flag = true; |
1132 | foreach ($branchpages as $branchpage) { |
1133 | if (array_key_exists($branchpage->id, $seenpages)) { // check if any of the pages have been viewed |
1134 | $flag = false; |
1135 | } |
1136 | } |
1137 | if ($flag && count($branchpages) > 0) { |
1138 | // add branch table |
1139 | $unseen[] = $clusterpage; |
1140 | } |
1141 | } else { |
1142 | // add any other type of page that has not already been viewed |
1143 | if (!array_key_exists($clusterpage->id, $seenpages)) { |
1144 | $unseen[] = $clusterpage; |
1145 | } |
1146 | } |
1147 | } |
1148 | |
1149 | if (count($unseen) > 0) { // it does not contain elements, then use exitjump, otherwise find out next page/branch |
1150 | $nextpage = $unseen[rand(0, count($unseen)-1)]; |
1151 | } else { |
1152 | return $exitjump; // seen all there is to see, leave the cluster |
1153 | } |
1154 | |
1155 | if ($nextpage->qtype == LESSON_BRANCHTABLE) { // if branch table, then pick a random page inside of it |
1156 | $branchpages = lesson_pages_in_branch($lessonpages, $nextpage->id); |
1157 | return $branchpages[rand(0, count($branchpages)-1)]->id; |
1158 | } else { // otherwise, return the page's id |
1159 | return $nextpage->id; |
1160 | } |
5e7856af |
1161 | } |
1162 | |
4b55d2af |
1163 | /** |
1164 | * Returns pages that are within a branch table and another branch table, end of branch or end of lesson |
1165 | * |
1166 | * @param array $lessonpages An array of lesson page objects. |
1167 | * @param int $branchid The id of the branch table that we would like the containing pages for. |
1168 | * @return array An array of lesson page objects. |
1169 | **/ |
5e7856af |
1170 | function lesson_pages_in_branch($lessonpages, $branchid) { |
ac8e16be |
1171 | $pageid = $lessonpages[$branchid]->nextpageid; // move to the first page after the branch table |
1172 | $pagesinbranch = array(); |
1173 | |
1174 | while (true) { |
1175 | if ($pageid == 0) { // EOL |
1176 | break; |
1177 | } elseif ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) { |
1178 | break; |
1179 | } elseif ($lessonpages[$pageid]->qtype == LESSON_ENDOFBRANCH) { |
1180 | break; |
1181 | } |
1182 | $pagesinbranch[] = $lessonpages[$pageid]; |
1183 | $pageid = $lessonpages[$pageid]->nextpageid; |
1184 | } |
1185 | |
1186 | return $pagesinbranch; |
5e7856af |
1187 | } |
1188 | |
4b55d2af |
1189 | /** |
1190 | * Interprets the LESSON_UNSEENBRANCHPAGE jump. |
1191 | * |
1192 | * will return the pageid of a random unseen page that is within a branch |
1193 | * |
1194 | * @see lesson_pages_in_branch() |
1195 | * @param int $lesson Id of the lesson. |
f521f98a |
1196 | * @param int $userid Id of the user. |
4b55d2af |
1197 | * @param int $pageid Id of the page from which we are jumping. |
1198 | * @return int Id of the next page. |
4b55d2af |
1199 | **/ |
5e7856af |
1200 | function lesson_unseen_question_jump($lesson, $user, $pageid) { |
646fc290 |
1201 | global $DB; |
1202 | |
ac8e16be |
1203 | // get the number of retakes |
318e3745 |
1204 | if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson, "userid"=>$user))) { |
ac8e16be |
1205 | $retakes = 0; |
1206 | } |
1207 | |
1208 | // get all the lesson_attempts aka what the user has seen |
646fc290 |
1209 | $params = array ("lessonid" => $lesson, "userid" => $user, "retry" => $retakes); |
1210 | if ($viewedpages = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params, "timeseen DESC")) { |
ac8e16be |
1211 | foreach($viewedpages as $viewed) { |
1212 | $seenpages[] = $viewed->pageid; |
1213 | } |
1214 | } else { |
1215 | $seenpages = array(); |
1216 | } |
1217 | |
1218 | // get the lesson pages |
e57bc529 |
1219 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
86f93345 |
1220 | print_error('cannotfindpages', 'lesson'); |
ac8e16be |
1221 | } |
1222 | |
1223 | if ($pageid == LESSON_UNSEENBRANCHPAGE) { // this only happens when a student leaves in the middle of an unseen question within a branch series |
1224 | $pageid = $seenpages[0]; // just change the pageid to the last page viewed inside the branch table |
1225 | } |
1226 | |
1227 | // go up the pages till branch table |
1228 | while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page |
1229 | if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) { |
1230 | break; |
1231 | } |
1232 | $pageid = $lessonpages[$pageid]->prevpageid; |
1233 | } |
1234 | |
1235 | $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid); |
1236 | |
1237 | // this foreach loop stores all the pages that are within the branch table but are not in the $seenpages array |
1238 | $unseen = array(); |
1239 | foreach($pagesinbranch as $page) { |
1240 | if (!in_array($page->id, $seenpages)) { |
1241 | $unseen[] = $page->id; |
1242 | } |
1243 | } |
1244 | |
1245 | if(count($unseen) == 0) { |
1246 | if(isset($pagesinbranch)) { |
1247 | $temp = end($pagesinbranch); |
1248 | $nextpage = $temp->nextpageid; // they have seen all the pages in the branch, so go to EOB/next branch table/EOL |
1249 | } else { |
1250 | // there are no pages inside the branch, so return the next page |
1251 | $nextpage = $lessonpages[$pageid]->nextpageid; |
1252 | } |
1253 | if ($nextpage == 0) { |
1254 | return LESSON_EOL; |
1255 | } else { |
1256 | return $nextpage; |
1257 | } |
1258 | } else { |
1259 | return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page |
1260 | } |
5e7856af |
1261 | } |
1262 | |
4b55d2af |
1263 | /** |
1264 | * Handles the unseen branch table jump. |
1265 | * |
f521f98a |
1266 | * @param int $lessonid Lesson id. |
1267 | * @param int $userid User id. |
4b55d2af |
1268 | * @return int Will return the page id of a branch table or end of lesson |
4b55d2af |
1269 | **/ |
362f2ce9 |
1270 | function lesson_unseen_branch_jump($lessonid, $userid) { |
646fc290 |
1271 | global $DB; |
1272 | |
318e3745 |
1273 | if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lessonid, "userid"=>$userid))) { |
ac8e16be |
1274 | $retakes = 0; |
1275 | } |
1276 | |
646fc290 |
1277 | $params = array ("lessonid" => $lessonid, "userid" => $userid, "retry" => $retakes); |
1278 | if (!$seenbranches = $DB->get_records_select("lesson_branch", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params, |
ac8e16be |
1279 | "timeseen DESC")) { |
86f93345 |
1280 | print_error('cannotfindrecords', 'lesson'); |
ac8e16be |
1281 | } |
1282 | |
1283 | // get the lesson pages |
e57bc529 |
1284 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
86f93345 |
1285 | print_error('cannotfindpages', 'lesson'); |
ac8e16be |
1286 | } |
1287 | |
1288 | // this loads all the viewed branch tables into $seen untill it finds the branch table with the flag |
1289 | // which is the branch table that starts the unseenbranch function |
1290 | $seen = array(); |
1291 | foreach ($seenbranches as $seenbranch) { |
1292 | if (!$seenbranch->flag) { |
1293 | $seen[$seenbranch->pageid] = $seenbranch->pageid; |
1294 | } else { |
1295 | $start = $seenbranch->pageid; |
1296 | break; |
1297 | } |
1298 | } |
1299 | // this function searches through the lesson pages to find all the branch tables |
1300 | // that follow the flagged branch table |
1301 | $pageid = $lessonpages[$start]->nextpageid; // move down from the flagged branch table |
1302 | while ($pageid != 0) { // grab all of the branch table till eol |
1303 | if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) { |
1304 | $branchtables[] = $lessonpages[$pageid]->id; |
1305 | } |
1306 | $pageid = $lessonpages[$pageid]->nextpageid; |
1307 | } |
1308 | $unseen = array(); |
1309 | foreach ($branchtables as $branchtable) { |
1310 | // load all of the unseen branch tables into unseen |
1311 | if (!array_key_exists($branchtable, $seen)) { |
1312 | $unseen[] = $branchtable; |
1313 | } |
1314 | } |
1315 | if (count($unseen) > 0) { |
1316 | return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page |
1317 | } else { |
1318 | return LESSON_EOL; // has viewed all of the branch tables |
1319 | } |
5e7856af |
1320 | } |
1321 | |
4b55d2af |
1322 | /** |
1323 | * Handles the random jump between a branch table and end of branch or end of lesson (LESSON_RANDOMPAGE). |
1324 | * |
f521f98a |
1325 | * @param int $lessonid Lesson id. |
4b55d2af |
1326 | * @param int $pageid The id of the page that we are jumping from (?) |
1327 | * @return int The pageid of a random page that is within a branch table |
4b55d2af |
1328 | **/ |
f521f98a |
1329 | function lesson_random_question_jump($lessonid, $pageid) { |
646fc290 |
1330 | global $DB; |
1331 | |
ac8e16be |
1332 | // get the lesson pages |
646fc290 |
1333 | $params = array ("lessonid" => $lessonid); |
1334 | if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { |
86f93345 |
1335 | print_error('cannotfindpages', 'lesson'); |
ac8e16be |
1336 | } |
1337 | |
1338 | // go up the pages till branch table |
1339 | while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page |
1340 | |
1341 | if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) { |
1342 | break; |
1343 | } |
1344 | $pageid = $lessonpages[$pageid]->prevpageid; |
1345 | } |
1346 | |
1347 | // get the pages within the branch |
1348 | $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid); |
1349 | |
1350 | if(count($pagesinbranch) == 0) { |
1351 | // there are no pages inside the branch, so return the next page |
1352 | return $lessonpages[$pageid]->nextpageid; |
1353 | } else { |
1354 | return $pagesinbranch[rand(0, count($pagesinbranch)-1)]->id; // returns a random page id for the next page |
1355 | } |
5e7856af |
1356 | } |
1357 | |
4b55d2af |
1358 | /** |
1359 | * Check to see if a page is below a branch table (logically). |
1360 | * |
1361 | * Will return true if a branch table is found logically above the page. |
1362 | * Will return false if an end of branch, cluster or the beginning |
1363 | * of the lesson is found before a branch table. |
1364 | * |
1365 | * @param array $pages An array of lesson page objects. |
1366 | * @param int $pageid Id of the page for testing. |
1367 | * @return boolean |
1368 | */ |
5e7856af |
1369 | function lesson_is_page_in_branch($pages, $pageid) { |
ac8e16be |
1370 | $pageid = $pages[$pageid]->prevpageid; // move up one |
1371 | |
1372 | // go up the pages till branch table |
1373 | while (true) { |
1374 | if ($pageid == 0) { // ran into the beginning of the lesson |
1375 | return false; |
1376 | } elseif ($pages[$pageid]->qtype == LESSON_ENDOFBRANCH) { // ran into the end of another branch table |
1377 | return false; |
1378 | } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // do not look beyond a cluster |
1379 | return false; |
1380 | } elseif ($pages[$pageid]->qtype == LESSON_BRANCHTABLE) { // hit a branch table |
1381 | return true; |
1382 | } |
1383 | $pageid = $pages[$pageid]->prevpageid; |
1384 | } |
5e7856af |
1385 | |
1386 | } |
1387 | |
4b55d2af |
1388 | /** |
1389 | * Check to see if a page is below a cluster page (logically). |
1390 | * |
1391 | * Will return true if a cluster is found logically above the page. |
1392 | * Will return false if an end of cluster or the beginning |
1393 | * of the lesson is found before a cluster page. |
1394 | * |
1395 | * @param array $pages An array of lesson page objects. |
1396 | * @param int $pageid Id of the page for testing. |
1397 | * @return boolean |
1398 | */ |
5e7856af |
1399 | function lesson_is_page_in_cluster($pages, $pageid) { |
ac8e16be |
1400 | $pageid = $pages[$pageid]->prevpageid; // move up one |
1401 | |
1402 | // go up the pages till branch table |
1403 | while (true) { |
1404 | if ($pageid == 0) { // ran into the beginning of the lesson |
1405 | return false; |
1406 | } elseif ($pages[$pageid]->qtype == LESSON_ENDOFCLUSTER) { // ran into the end of another branch table |
1407 | return false; |
1408 | } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // hit a branch table |
1409 | return true; |
1410 | } |
1411 | $pageid = $pages[$pageid]->prevpageid; |
1412 | } |
5e7856af |
1413 | } |
1414 | |
4b55d2af |
1415 | /** |
1416 | * Calculates a user's grade for a lesson. |
1417 | * |
4b55d2af |
1418 | * @param object $lesson The lesson that the user is taking. |
4b55d2af |
1419 | * @param int $retries The attempt number. |
88427c07 |
1420 | * @param int $userid Id of the user (optinal, default current user). |
1421 | * @return object { nquestions => number of questions answered |
1422 | attempts => number of question attempts |
1423 | total => max points possible |
1424 | earned => points earned by student |
1425 | grade => calculated percentage grade |
1426 | nmanual => number of manually graded questions |
1427 | manualpoints => point value for manually graded questions } |
4b55d2af |
1428 | */ |
88427c07 |
1429 | function lesson_grade($lesson, $ntries, $userid = 0) { |
646fc290 |
1430 | global $USER, $DB; |
ac8e16be |
1431 | |
88427c07 |
1432 | if (empty($userid)) { |
1433 | $userid = $USER->id; |
1434 | } |
1435 | |
1436 | // Zero out everything |
1437 | $ncorrect = 0; |
1438 | $nviewed = 0; |
1439 | $score = 0; |
1440 | $nmanual = 0; |
1441 | $manualpoints = 0; |
1442 | $thegrade = 0; |
1443 | $nquestions = 0; |
1444 | $total = 0; |
1445 | $earned = 0; |
1446 | |
646fc290 |
1447 | $params = array ("lessonid" => $lesson->id, "userid" => $userid, "retry" => $ntries); |
1448 | if ($useranswers = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND |
1449 | userid = :userid AND retry = :retry", $params, "timeseen")) { |
88427c07 |
1450 | // group each try with its page |
1451 | $attemptset = array(); |
1452 | foreach ($useranswers as $useranswer) { |
1453 | $attemptset[$useranswer->pageid][] = $useranswer; |
ac8e16be |
1454 | } |
88427c07 |
1455 | |
1456 | // Drop all attempts that go beyond max attempts for the lesson |
1457 | foreach ($attemptset as $key => $set) { |
1458 | $attemptset[$key] = array_slice($set, 0, $lesson->maxattempts); |
1459 | } |
1460 | |
88427c07 |
1461 | // get only the pages and their answers that the user answered |
646fc290 |
1462 | list($usql, $parameters) = $DB->get_in_or_equal(array_keys($attemptset)); |
1463 | $parameters["lessonid"] = $lesson->id; |
1464 | $pages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid AND id $usql", $parameters); |
1465 | $answers = $DB->get_records_select("lesson_answers", "lessonid = :lessonid AND pageid $usql", $parameters); |
88427c07 |
1466 | |
1467 | // Number of pages answered |
1468 | $nquestions = count($pages); |
1469 | |
1470 | foreach ($attemptset as $attempts) { |
1471 | if ($lesson->custom) { |
1472 | $attempt = end($attempts); |
1473 | // If essay question, handle it, otherwise add to score |
1474 | if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) { |
ac8e16be |
1475 | $essayinfo = unserialize($attempt->useranswer); |
88427c07 |
1476 | $earned += $essayinfo->score; |
1477 | $nmanual++; |
1478 | $manualpoints += $answers[$attempt->answerid]->score; |
ab1e7c39 |
1479 | } else if (!empty($attempt->answerid)) { |
88427c07 |
1480 | $earned += $answers[$attempt->answerid]->score; |
1481 | } |
1482 | } else { |
1483 | foreach ($attempts as $attempt) { |
1484 | $earned += $attempt->correct; |
1485 | } |
1486 | $attempt = end($attempts); // doesn't matter which one |
1487 | // If essay question, increase numbers |
1488 | if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) { |
1489 | $nmanual++; |
1490 | $manualpoints++; |
ac8e16be |
1491 | } |
1492 | } |
88427c07 |
1493 | // Number of times answered |
1494 | $nviewed += count($attempts); |
1495 | } |
1496 | |
1497 | if ($lesson->custom) { |
ac8e16be |
1498 | $bestscores = array(); |
88427c07 |
1499 | // Find the highest possible score per page to get our total |
1500 | foreach ($answers as $answer) { |
46341ab7 |
1501 | if(!isset($bestscores[$answer->pageid])) { |
88427c07 |
1502 | $bestscores[$answer->pageid] = $answer->score; |
46341ab7 |
1503 | } else if ($bestscores[$answer->pageid] < $answer->score) { |
88427c07 |
1504 | $bestscores[$answer->pageid] = $answer->score; |
ac8e16be |
1505 | } |
1506 | } |
88427c07 |
1507 | $total = array_sum($bestscores); |
1508 | } else { |
1509 | // Check to make sure the student has answered the minimum questions |
1510 | if ($lesson->minquestions and $nquestions < $lesson->minquestions) { |
1511 | // Nope, increase number viewed by the amount of unanswered questions |
1512 | $total = $nviewed + ($lesson->minquestions - $nquestions); |
1513 | } else { |
1514 | $total = $nviewed; |
1515 | } |
ac8e16be |
1516 | } |
88427c07 |
1517 | } |
1518 | |
1519 | if ($total) { // not zero |
1520 | $thegrade = round(100 * $earned / $total, 5); |
1521 | } |
1522 | |
1523 | // Build the grade information object |
1524 | $gradeinfo = new stdClass; |
1525 | $gradeinfo->nquestions = $nquestions; |
1526 | $gradeinfo->attempts = $nviewed; |
1527 | $gradeinfo->total = $total; |
1528 | $gradeinfo->earned = $earned; |
1529 | $gradeinfo->grade = $thegrade; |
1530 | $gradeinfo->nmanual = $nmanual; |
1531 | $gradeinfo->manualpoints = $manualpoints; |
1532 | |
1533 | return $gradeinfo; |
1534 | } |
1535 | |
1536 | /** |
1537 | * Prints the on going message to the user. |
1538 | * |
1539 | * With custom grading On, displays points |
1540 | * earned out of total points possible thus far. |
1541 | * With custom grading Off, displays number of correct |
1542 | * answers out of total attempted. |
1543 | * |
1544 | * @param object $lesson The lesson that the user is taking. |
1545 | * @return void |
1546 | **/ |
1547 | function lesson_print_ongoing_score($lesson) { |
318e3745 |
1548 | global $USER, $DB; |
1549 | |
6e1ff5c8 |
1550 | $cm = get_coursemodule_from_instance('lesson', $lesson->id); |
1551 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
1552 | |
1553 | if (has_capability('mod/lesson:manage', $context)) { |
88427c07 |
1554 | echo "<p align=\"center\">".get_string('teacherongoingwarning', 'lesson').'</p>'; |
1555 | } else { |
318e3745 |
1556 | $ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id)); |
88427c07 |
1557 | if (isset($USER->modattempts[$lesson->id])) { |
1558 | $ntries--; |
1559 | } |
1560 | $gradeinfo = lesson_grade($lesson, $ntries); |
ac8e16be |
1561 | |
88427c07 |
1562 | $a = new stdClass; |
1563 | if ($lesson->custom) { |
1564 | $a->score = $gradeinfo->earned; |
1565 | $a->currenthigh = $gradeinfo->total; |
1566 | print_simple_box(get_string("ongoingcustom", "lesson", $a), "center"); |
ac8e16be |
1567 | } else { |
88427c07 |
1568 | $a->correct = $gradeinfo->earned; |
1569 | $a->viewed = $gradeinfo->attempts; |
1570 | print_simple_box(get_string("ongoingnormal", "lesson", $a), "center"); |
ac8e16be |
1571 | } |
1572 | } |
5e7856af |
1573 | } |
1574 | |
4b55d2af |
1575 | /** |
1576 | * Prints tabs for the editing and adding pages. Each tab is a question type. |
1577 | * |
1578 | * @param array $qtypes The question types array (may not need to pass this because it is defined in this file) |
1579 | * @param string $selected Current selected tab |
1580 | * @param string $link The base href value of the link for the tab |
1581 | * @param string $onclick Javascript for the tab link |
1582 | * @return void |
1583 | */ |
5e7856af |
1584 | function lesson_qtype_menu($qtypes, $selected="", $link="", $onclick="") { |
271fea97 |
1585 | $tabs = array(); |
1586 | $tabrows = array(); |
1587 | |
9638a1f4 |
1588 | foreach ($qtypes as $qtype => $qtypename) { |
4085962a |
1589 | $tabrows[] = new tabobject($qtype, "$link&qtype=$qtype\" onclick=\"$onclick", $qtypename); |
ac8e16be |
1590 | } |
271fea97 |
1591 | $tabs[] = $tabrows; |
1592 | print_tabs($tabs, $selected); |
1593 | echo "<input type=\"hidden\" name=\"qtype\" value=\"$selected\" /> \n"; |
9638a1f4 |
1594 | |
5e7856af |
1595 | } |
1596 | |
62eda6ea |
1597 | /** |
1598 | * Prints out a Progress Bar which depicts a user's progress within a lesson. |
1599 | * |
1600 | * Currently works best with a linear lesson. Clusters are counted as a single page. |
1601 | * Also, only viewed branch tables and questions that have been answered correctly count |
1602 | * toward lesson completion (or progress). Only Students can see the Progress bar as well. |
1603 | * |
1604 | * @param object $lesson The lesson that the user is currently taking. |
1605 | * @param object $course The course that the to which the lesson belongs. |
1606 | * @return boolean The return is not significant as of yet. Will return true/false. |
62eda6ea |
1607 | **/ |
1608 | function lesson_print_progress_bar($lesson, $course) { |
646fc290 |
1609 | global $CFG, $USER, $DB; |
318e3745 |
1610 | |
6e1ff5c8 |
1611 | $cm = get_coursemodule_from_instance('lesson', $lesson->id); |
1612 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
1613 | |
62eda6ea |
1614 | // lesson setting to turn progress bar on or off |
1615 | if (!$lesson->progressbar) { |
1616 | return false; |
1617 | } |
1618 | |
1619 | // catch teachers |
6e1ff5c8 |
1620 | if (has_capability('mod/lesson:manage', $context)) { |
9101efd3 |
1621 | notify(get_string('progressbarteacherwarning2', 'lesson')); |
62eda6ea |
1622 | return false; |
1623 | } |
acab9099 |
1624 | if (!isset($USER->modattempts[$lesson->id])) { |
1625 | // all of the lesson pages |
646fc290 |
1626 | if (!$pages = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id))) { |
acab9099 |
1627 | return false; |
1628 | } else { |
1629 | foreach ($pages as $page) { |
1630 | if ($page->prevpageid == 0) { |
1631 | $pageid = $page->id; // find the first page id |
1632 | break; |
1633 | } |
62eda6ea |
1634 | } |
1635 | } |
62eda6ea |
1636 | |
acab9099 |
1637 | // current attempt number |
318e3745 |
1638 | if (!$ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id))) { |
acab9099 |
1639 | $ntries = 0; // may not be necessary |
1640 | } |
62eda6ea |
1641 | |
acab9099 |
1642 | $viewedpageids = array(); |
62eda6ea |
1643 | |
acab9099 |
1644 | // collect all of the correctly answered questions |
646fc290 |
1645 | $params = array ("lessonid" => $lesson->id, "userid" => $USER->id, "retry" => $ntries); |
1646 | if ($viewedpages = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND userid = :userid AND retry = :retry AND correct = 1", $params, 'timeseen DESC', 'pageid, id')) { |
acab9099 |
1647 | $viewedpageids = array_keys($viewedpages); |
1648 | } |
1649 | // collect all of the branch tables viewed |
646fc290 |
1650 | if ($viewedbranches = $DB->get_records_select("lesson_branch", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params, 'timeseen DESC', 'pageid, id')) { |
acab9099 |
1651 | $viewedpageids = array_merge($viewedpageids, array_keys($viewedbranches)); |
1652 | } |
1653 | |
1654 | // Filter out the following pages: |
1655 | // End of Cluster |
1656 | // End of Branch |
1657 | // Pages found inside of Clusters |
1658 | // Do not filter out Cluster Page(s) because we count a cluster as one. |
1659 | // By keeping the cluster page, we get our 1 |
1660 | $validpages = array(); |
1661 | while ($pageid != 0) { |
1662 | if ($pages[$pageid]->qtype == LESSON_CLUSTER) { |
1663 | $clusterpageid = $pageid; // copy it |
1664 | $validpages[$clusterpageid] = 1; // add the cluster page as a valid page |
1665 | $pageid = $pages[$pageid]->nextpageid; // get next page |
62eda6ea |
1666 | |
acab9099 |
1667 | // now, remove all necessary viewed paged ids from the viewedpageids array. |
1668 | while ($pages[$pageid]->qtype != LESSON_ENDOFCLUSTER and $pageid != 0) { |
1669 | if (in_array($pageid, $viewedpageids)) { |
1670 | unset($viewedpageids[array_search($pageid, $viewedpageids)]); // remove it |
1671 | // since the user did see one page in the cluster, add the cluster pageid to the viewedpageids |
1672 | if (!in_array($clusterpageid, $viewedpageids)) { |
1673 | $viewedpageids[] = $clusterpageid; |
1674 | } |
62eda6ea |
1675 | } |
acab9099 |
1676 | $pageid = $pages[$pageid]->nextpageid; |
62eda6ea |
1677 | } |
acab9099 |
1678 | } elseif ($pages[$pageid]->qtype == LESSON_ENDOFCLUSTER or $pages[$pageid]->qtype == LESSON_ENDOFBRANCH) { |
1679 | // dont count these, just go to next |
1680 | $pageid = $pages[$pageid]->nextpageid; |
1681 | } else { |
1682 | // a counted page |
1683 | $validpages[$pageid] = 1; |
62eda6ea |
1684 | $pageid = $pages[$pageid]->nextpageid; |
1685 | } |
acab9099 |
1686 | } |
62eda6ea |
1687 | |
acab9099 |
1688 | // progress calculation as a percent |
1689 | $progress = round(count($viewedpageids)/count($validpages), 2) * 100; |
1690 | } else { |
1691 | $progress = 100; |
1692 | } |
62eda6ea |
1693 | |
1694 | // print out the Progress Bar. Attempted to put as much as possible in the style sheets. |
1695 | echo '<div class="progress_bar" align="center">'; |
1696 | echo '<table class="progress_bar_table"><tr>'; |
1697 | if ($progress != 0) { // some browsers do not repsect the 0 width. |
4085962a |
1698 | echo '<td style="width:'.$progress.'%;" class="progress_bar_completed">'; |
62eda6ea |
1699 | echo '</td>'; |
1700 | } |
1701 | echo '<td class="progress_bar_todo">'; |
1702 | echo '<div class="progress_bar_token"></div>'; |
1703 | echo '</td>'; |
1704 | echo '</tr></table>'; |
1705 | echo '</div>'; |
1706 | |
1707 | return true; |
1708 | } |
1709 | |
1710 | /** |
1711 | * Determines if a user can view the left menu. The determining factor |
1712 | * is whether a user has a grade greater than or equal to the lesson setting |
1713 | * of displayleftif |
1714 | * |
1715 | * @param object $lesson Lesson object of the current lesson |
1716 | * @return boolean 0 if the user cannot see, or $lesson->displayleft to keep displayleft unchanged |
62eda6ea |
1717 | **/ |
1718 | function lesson_displayleftif($lesson) { |
646fc290 |
1719 | global $CFG, $USER, $DB; |
62eda6ea |
1720 | |
1721 | if (!empty($lesson->displayleftif)) { |
1722 | // get the current user's max grade for this lesson |
646fc290 |
1723 | $params = array ("userid" => $USER->id, "lessonid" => $lesson->id); |
1724 | if ($maxgrade = $DB->get_record_sql('SELECT userid, MAX(grade) AS maxgrade FROM {lesson_grades} WHERE userid = :userid AND lessonid = :lessonid GROUP BY userid', $params)) { |
62eda6ea |
1725 | if ($maxgrade->maxgrade < $lesson->displayleftif) { |
1726 | return 0; // turn off the displayleft |
1727 | } |
1728 | } else { |
1729 | return 0; // no grades |
1730 | } |
1731 | } |
1732 | |
1733 | // if we get to here, keep the original state of displayleft lesson setting |
1734 | return $lesson->displayleft; |
1735 | } |
5e7856af |
1736 | |
f521f98a |
1737 | /** |
1738 | * If there is a media file associated with this |
1739 | * lesson, then print it in a block. |
1740 | * |
1741 | * @param int $cmid Course Module ID for this lesson |
1742 | * @param object $lesson Full lesson record object |
1743 | * @return void |
1744 | **/ |
888f0c54 |
1745 | function lesson_print_mediafile_block($cmid, $lesson) { |
f521f98a |
1746 | if (!empty($lesson->mediafile)) { |
1747 | $url = '/mod/lesson/mediafile.php?id='.$cmid; |
1748 | $options = 'menubar=0,location=0,left=5,top=5,scrollbars,resizable,width='. $lesson->mediawidth .',height='. $lesson->mediaheight; |
1749 | $name = 'lessonmediafile'; |
1750 | |
1751 | $content = link_to_popup_window ($url, $name, get_string('mediafilepopup', 'lesson'), '', '', get_string('mediafilepopup', 'lesson'), $options, true); |
1752 | $content .= helpbutton("mediafilestudent", get_string("mediafile", "lesson"), "lesson", true, false, '', true); |
1753 | |
1754 | print_side_block(get_string('linkedmedia', 'lesson'), $content, NULL, NULL, '', array('class' => 'mediafile'), get_string('linkedmedia', 'lesson')); |
1755 | } |
1756 | } |
1757 | |
1758 | /** |
1759 | * If a timed lesson and not a teacher, then |
1760 | * print the clock |
1761 | * |
1762 | * @param int $cmid Course Module ID for this lesson |
1763 | * @param object $lesson Full lesson record object |
1764 | * @param object $timer Full timer record object |
1765 | * @return void |
1766 | **/ |
888f0c54 |
1767 | function lesson_print_clock_block($cmid, $lesson, $timer) { |
ba458143 |
1768 | global $CFG, $PAGE; |
f521f98a |
1769 | |
1770 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
1771 | |
1772 | // Display for timed lessons and for students only |
1773 | if($lesson->timed and !has_capability('mod/lesson:manage', $context) and !empty($timer)) { |
ba458143 |
1774 | |
1775 | $clocksettings = Array('starttime'=>$timer->starttime, 'servertime'=>time(),'testlength'=>($lesson->maxtime * 60)); |
1776 | $content = $PAGE->requires->data_for_js('clocksettings', $clocksettings)->asap(); |
1777 | $content .= $PAGE->requires->js('mod/lesson/timer.js')->asap(); |
1778 | $content .= $PAGE->requires->js_function_call('show_clock')->asap(); |
1779 | $content .= '<div class="jshidewhenenabled">'; |
f521f98a |
1780 | $content .= lesson_print_time_remaining($timer->starttime, $lesson->maxtime, true)."\n"; |
ba458143 |
1781 | $content .= '</div>'; |
1782 | |
f521f98a |
1783 | print_side_block(get_string('timeremaining', 'lesson'), $content, NULL, NULL, '', array('class' => 'clock'), get_string('timeremaining', 'lesson')); |
1784 | } |
1785 | } |
1786 | |
1787 | /** |
1788 | * If left menu is turned on, then this will |
1789 | * print the menu in a block |
1790 | * |
1791 | * @param int $cmid Course Module ID for this lesson |
1792 | * @param object $lesson Full lesson record object |
1793 | * @return void |
1794 | **/ |
888f0c54 |
1795 | function lesson_print_menu_block($cmid, $lesson) { |
646fc290 |
1796 | global $CFG, $DB; |
f521f98a |
1797 | |
1798 | if ($lesson->displayleft) { |
646fc290 |
1799 | $pageid = $DB->get_field('lesson_pages', 'id', array('lessonid' => $lesson->id, 'prevpageid' => 0)); |
1800 | $params = array ("lessonid" => $lesson->id); |
1801 | $pages = $DB->get_records_select('lesson_pages', "lessonid = :lessonid", $params); |
f521f98a |
1802 | $currentpageid = optional_param('pageid', $pageid, PARAM_INT); |
1803 | |
1804 | if ($pageid and $pages) { |
1805 | $content = '<a href="#maincontent" class="skip">'.get_string('skip', 'lesson')."</a>\n<div class=\"menuwrapper\">\n<ul>\n"; |
1806 | |
1807 | while ($pageid != 0) { |
1808 | $page = $pages[$pageid]; |
1809 | |
1810 | // Only process branch tables with display turned on |
1811 | if ($page->qtype == LESSON_BRANCHTABLE and $page->display) { |
1812 | if ($page->id == $currentpageid) { |
1813 | $content .= '<li class="selected">'.format_string($page->title,true)."</a></li>\n"; |
1814 | } else { |
1815 | $content .= "<li class=\"notselected\"><a href=\"$CFG->wwwroot/mod/lesson/view.php?id=$cmid&pageid=$page->id\">".format_string($page->title,true)."</a></li>\n"; |
1816 | } |
1817 | |
1818 | } |
1819 | $pageid = $page->nextpageid; |
1820 | } |
1821 | $content .= "</ul>\n</div>\n"; |
1822 | print_side_block(get_string('lessonmenu', 'lesson'), $content, NULL, NULL, '', array('class' => 'menu'), get_string('lessonmenu', 'lesson')); |
1823 | } |
1824 | } |
1825 | } |
1826 | |
888f0c54 |
1827 | /** |
1828 | * This is not ideal, but checks to see if a |
1829 | * column has "block" content. |
1830 | * |
1831 | * In the future, it would be nice if the lesson |
1832 | * media file, timer and navigation were blocks |
1833 | * then this would be unnecessary. |
1834 | * |
1835 | * @uses $CFG |
1836 | * @uses $PAGE |
1837 | * @param object $lesson Full lesson record object |
1838 | * @param array $pageblocks An array of block instances organized by left and right columns |
1839 | * @param string $column Pass either BLOCK_POS_RIGHT or BLOCK_POS_LEFT constants |
1840 | * @return boolean |
1841 | **/ |
1842 | function lesson_blocks_have_content($lesson, $pageblocks, $column) { |
1843 | global $CFG, $PAGE; |
1844 | |
1845 | // First check lesson conditions |
1846 | if ($column == BLOCK_POS_RIGHT) { |
1847 | $managecap = false; |
1848 | if ($cm = get_coursemodule_from_instance('lesson', $lesson->id, $lesson->course)) { |
1849 | $managecap = has_capability('mod/lesson:manage', get_context_instance(CONTEXT_MODULE, $cm->id)); |
1850 | } |
1851 | if (($lesson->timed and !$managecap) or !empty($lesson->mediafile)) { |
1852 | return true; |
1853 | } |
1854 | } else if ($column == BLOCK_POS_LEFT) { |
1855 | if ($lesson->displayleft) { |
1856 | return true; |
1857 | } |
1858 | } |
1859 | if (!empty($CFG->showblocksonmodpages)) { |
1860 | if ((blocks_have_content($pageblocks, $column) || $PAGE->user_is_editing())) { |
1861 | return true; |
1862 | } |
1863 | } |
1864 | |
1865 | return false; |
1866 | } |
1867 | |
2a488ba5 |
1868 | ?> |