Only send contexts to cache if the aren't empty. At initial installations
[moodle.git] / mod / lesson / locallib.php
CommitLineData
9fcf51d9 1<?php // $Id$
62eda6ea 2/// mnielsen
5e7856af 3/// locallib.php is the new lib file for lesson module.
4/// including locallib.php is the same as including the old lib.php
4b55d2af 5
6/**
7* Next page -> any page not seen before
8*/
5e7856af 9if (!defined("LESSON_UNSEENPAGE")) {
ac8e16be 10 define("LESSON_UNSEENPAGE", 1); // Next page -> any page not seen before
4b55d2af 11}
12/**
13* Next page -> any page not answered correctly
14*/
5e7856af 15if (!defined("LESSON_UNANSWEREDPAGE")) {
ac8e16be 16 define("LESSON_UNANSWEREDPAGE", 2); // Next page -> any page not answered correctly
4b55d2af 17}
5e7856af 18
4b55d2af 19/**
20* Define different lesson flows for next page
21*/
5e7856af 22$LESSON_NEXTPAGE_ACTION = array (0 => get_string("normal", "lesson"),
23 LESSON_UNSEENPAGE => get_string("showanunseenpage", "lesson"),
24 LESSON_UNANSWEREDPAGE => get_string("showanunansweredpage", "lesson") );
25
4b55d2af 26// Lesson jump types defined
27// TODO: instead of using define statements, create an array with all the jump values
5e7856af 28
4b55d2af 29/**
30 * Jump to Next Page
31 */
5e7856af 32if (!defined("LESSON_NEXTPAGE")) {
4b55d2af 33 define("LESSON_NEXTPAGE", -1);
34}
35/**
36 * End of Lesson
37 */
5e7856af 38if (!defined("LESSON_EOL")) {
4b55d2af 39 define("LESSON_EOL", -9);
40}
41/**
42 * Jump to an unseen page within a branch and end of branch or end of lesson
43 */
5e7856af 44if (!defined("LESSON_UNSEENBRANCHPAGE")) {
4b55d2af 45 define("LESSON_UNSEENBRANCHPAGE", -50);
46}
47/**
48 * Jump to Previous Page
49 */
5e7856af 50if (!defined("LESSON_PREVIOUSPAGE")) {
4b55d2af 51 define("LESSON_PREVIOUSPAGE", -40);
52}
53/**
54 * Jump to a random page within a branch and end of branch or end of lesson
55 */
5e7856af 56if (!defined("LESSON_RANDOMPAGE")) {
4b55d2af 57 define("LESSON_RANDOMPAGE", -60);
58}
59/**
60 * Jump to a random Branch
61 */
5e7856af 62if (!defined("LESSON_RANDOMBRANCH")) {
4b55d2af 63 define("LESSON_RANDOMBRANCH", -70);
64}
65/**
66 * Cluster Jump
67 */
5e7856af 68if (!defined("LESSON_CLUSTERJUMP")) {
4b55d2af 69 define("LESSON_CLUSTERJUMP", -80);
70}
71/**
72 * Undefined
73 */
5e7856af 74if (!defined("LESSON_UNDEFINED")) {
4b55d2af 75 define("LESSON_UNDEFINED", -99);
76}
77
78// Lesson question types defined
5e7856af 79
4b55d2af 80/**
81 * Short answer question type
82 */
5e7856af 83if (!defined("LESSON_SHORTANSWER")) {
84 define("LESSON_SHORTANSWER", "1");
85}
4b55d2af 86/**
87 * True/False question type
88 */
5e7856af 89if (!defined("LESSON_TRUEFALSE")) {
90 define("LESSON_TRUEFALSE", "2");
91}
4b55d2af 92/**
93 * Multichoice question type
94 *
95 * If you change the value of this then you need
96 * to change it in restorelib.php as well.
97 */
98if (!defined("LESSON_MULTICHOICE")) {
5e7856af 99 define("LESSON_MULTICHOICE", "3");
100}
4b55d2af 101/**
102 * Random question type - not used
103 */
5e7856af 104if (!defined("LESSON_RANDOM")) {
105 define("LESSON_RANDOM", "4");
106}
4b55d2af 107/**
108 * Matching question type
109 *
110 * If you change the value of this then you need
111 * to change it in restorelib.php, in mysql.php
112 * and postgres7.php as well.
113 */
114if (!defined("LESSON_MATCHING")) {
b9869082 115 define("LESSON_MATCHING", "5");
5e7856af 116}
4b55d2af 117/**
118 * Not sure - not used
119 */
5e7856af 120if (!defined("LESSON_RANDOMSAMATCH")) {
121 define("LESSON_RANDOMSAMATCH", "6");
122}
4b55d2af 123/**
124 * Not sure - not used
125 */
5e7856af 126if (!defined("LESSON_DESCRIPTION")) {
127 define("LESSON_DESCRIPTION", "7");
128}
4b55d2af 129/**
130 * Numerical question type
131 */
5e7856af 132if (!defined("LESSON_NUMERICAL")) {
133 define("LESSON_NUMERICAL", "8");
134}
4b55d2af 135/**
136 * Multichoice with multianswer question type
137 */
5e7856af 138if (!defined("LESSON_MULTIANSWER")) {
139 define("LESSON_MULTIANSWER", "9");
140}
4b55d2af 141/**
142 * Essay question type
143 */
5e7856af 144if (!defined("LESSON_ESSAY")) {
ac8e16be 145 define("LESSON_ESSAY", "10");
5e7856af 146}
5e7856af 147
4b55d2af 148/**
149 * Lesson question type array.
150 * Contains all question types used
151 */
5e7856af 152$LESSON_QUESTION_TYPE = array ( LESSON_MULTICHOICE => get_string("multichoice", "quiz"),
153 LESSON_TRUEFALSE => get_string("truefalse", "quiz"),
154 LESSON_SHORTANSWER => get_string("shortanswer", "quiz"),
155 LESSON_NUMERICAL => get_string("numerical", "quiz"),
156 LESSON_MATCHING => get_string("match", "quiz"),
62eda6ea 157 LESSON_ESSAY => get_string("essay", "lesson")
5e7856af 158// LESSON_DESCRIPTION => get_string("description", "quiz"),
159// LESSON_RANDOM => get_string("random", "quiz"),
160// LESSON_RANDOMSAMATCH => get_string("randomsamatch", "quiz"),
161// LESSON_MULTIANSWER => get_string("multianswer", "quiz"),
162 );
163
4b55d2af 164// Non-question page types
165
166/**
167 * Branch Table page
168 */
5e7856af 169if (!defined("LESSON_BRANCHTABLE")) {
170 define("LESSON_BRANCHTABLE", "20");
171}
4b55d2af 172/**
173 * End of Branch page
174 */
5e7856af 175if (!defined("LESSON_ENDOFBRANCH")) {
176 define("LESSON_ENDOFBRANCH", "21");
177}
4b55d2af 178/**
179 * Start of Cluster page
180 */
181if (!defined("LESSON_CLUSTER")) {
182 define("LESSON_CLUSTER", "30");
183}
184/**
185 * End of Cluster page
186 */
187if (!defined("LESSON_ENDOFCLUSTER")) {
188 define("LESSON_ENDOFCLUSTER", "31");
189}
190
191// other variables...
5e7856af 192
4b55d2af 193/**
194 * Flag for the editor for the answer textarea.
195 */
5e7856af 196if (!defined("LESSON_ANSWER_EDITOR")) {
197 define("LESSON_ANSWER_EDITOR", "1");
198}
4b55d2af 199/**
200 * Flag for the editor for the response textarea.
201 */
5e7856af 202if (!defined("LESSON_RESPONSE_EDITOR")) {
203 define("LESSON_RESPONSE_EDITOR", "2");
204}
205
206//////////////////////////////////////////////////////////////////////////////////////
207/// Any other lesson functions go here. Each of them must have a name that
208/// starts with lesson_
209
9fcf51d9 210/**
211 * Print the standard header for lesson module
212 *
213 * @param object $cm Course module record object
214 * @param object $course Couse record object
215 * @param object $lesson Lesson module record object
216 * @param string $currenttab Current tab for the lesson tabs
217 * @param boolean $printheading Print the a heading with the lesson name
218 * @return void
219 **/
220function lesson_print_header($cm, $course, $lesson, $currenttab = '', $printheading = true) {
221 global $CFG, $USER;
222
223/// Header setup
224 if ($course->category) {
225 $navigation = "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\" title=\"$course->fullname\">$course->shortname</a> ->";
226 } else {
227 $navigation = '';
228 }
229
230 $strlessons = get_string('modulenameplural', 'lesson');
231 $strlesson = get_string('modulename', 'lesson');
232 $strname = format_string($lesson->name, true);
233
234/// Print header, heading, tabs and messages
235 print_header("$course->shortname: $strname", $course->fullname,
236 "$navigation <a href=\"index.php?id=$course->id\" title=\"$strlessons\">$strlessons</a> -> $strname",
237 '', '', true, update_module_button($cm->id, $course->id, $strlesson),
238 navmenu($course, $cm));
239
240 if ($printheading) {
241 print_heading_with_help(format_string($lesson->name, true), "overview", "lesson");
242 }
243
244 if (!empty($currenttab) and isteacher($course->id)) {
245 include($CFG->dirroot.'/mod/lesson/tabs.php');
246 }
247}
248
249/**
250 * Returns course module, course and module instance given
251 * either the course module ID or a lesson module ID.
252 *
253 * @param int $cmid Course Module ID
254 * @param int $lessonid Lesson module instance ID
255 * @return array array($cm, $course, $lesson)
256 **/
257function lesson_get_basics($cmid = 0, $lessonid = 0) {
258 if ($cmid) {
259 if (!$cm = get_record('course_modules', 'id', $cmid)) {
260 error('Course Module ID was incorrect');
261 }
262 if (!$course = get_record('course', 'id', $cm->course)) {
263 error('Course is misconfigured');
264 }
265 if (!$lesson = get_record('lesson', 'id', $cm->instance)) {
266 error('Course module is incorrect');
267 }
268 } else if ($lessonid) {
269 if (!$lesson = get_record('lesson', 'id', $lessonid)) {
270 error('Course module is incorrect');
271 }
272 if (!$course = get_record('course', 'id', $lesson->course)) {
273 error('Course is misconfigured');
274 }
275 if (!$cm = get_coursemodule_from_instance('lesson', $lesson->id, $course->id)) {
276 error('Course Module ID was incorrect');
277 }
278 } else {
279 error('No course module ID or lesson ID were passed');
280 }
281
282 return array($cm, $course, $lesson);
283}
284
4b55d2af 285/**
286 * Given some question info and some data about the the answers
287 * this function parses, organises and saves the question
288 *
289 * This is only used when IMPORTING questions and is only called
290 * from format.php
291 * Lifted from mod/quiz/lib.php -
292 * 1. all reference to oldanswers removed
293 * 2. all reference to quiz_multichoice table removed
294 * 3. In SHORTANSWER questions usecase is store in the qoption field
295 * 4. In NUMERIC questions store the range as two answers
296 * 5. TRUEFALSE options are ignored
297 * 6. For MULTICHOICE questions with more than one answer the qoption field is true
298 *
299 * @param opject $question Contains question data like question, type and answers.
300 * @return object Returns $result->error or $result->notice.
301 **/
5e7856af 302function lesson_save_question_options($question) {
5e7856af 303
304 $timenow = time();
305 switch ($question->qtype) {
306 case LESSON_SHORTANSWER:
307
308 $answers = array();
309 $maxfraction = -1;
310
311 // Insert all the new answers
312 foreach ($question->answer as $key => $dataanswer) {
313 if ($dataanswer != "") {
f7ffb898 314 $answer = new stdClass;
5e7856af 315 $answer->lessonid = $question->lessonid;
316 $answer->pageid = $question->id;
317 if ($question->fraction[$key] >=0.5) {
318 $answer->jumpto = LESSON_NEXTPAGE;
319 }
320 $answer->timecreated = $timenow;
321 $answer->grade = $question->fraction[$key] * 100;
322 $answer->answer = $dataanswer;
c87a341c 323 $answer->response = $question->feedback[$key];
5e7856af 324 if (!$answer->id = insert_record("lesson_answers", $answer)) {
325 $result->error = "Could not insert shortanswer quiz answer!";
326 return $result;
327 }
328 $answers[] = $answer->id;
329 if ($question->fraction[$key] > $maxfraction) {
330 $maxfraction = $question->fraction[$key];
331 }
332 }
333 }
334
335
336 /// Perform sanity checks on fractional grades
337 if ($maxfraction != 1) {
338 $maxfraction = $maxfraction * 100;
339 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
340 return $result;
341 }
342 break;
343
344 case LESSON_NUMERICAL: // Note similarities to SHORTANSWER
345
346 $answers = array();
347 $maxfraction = -1;
348
349
350 // for each answer store the pair of min and max values even if they are the same
351 foreach ($question->answer as $key => $dataanswer) {
352 if ($dataanswer != "") {
f7ffb898 353 $answer = new stdClass;
5e7856af 354 $answer->lessonid = $question->lessonid;
355 $answer->pageid = $question->id;
356 $answer->jumpto = LESSON_NEXTPAGE;
357 $answer->timecreated = $timenow;
358 $answer->grade = $question->fraction[$key] * 100;
dd192b26 359 $min = $question->answer[$key] - $question->tolerance[$key];
360 $max = $question->answer[$key] + $question->tolerance[$key];
361 $answer->answer = $min.":".$max;
362 // $answer->answer = $question->min[$key].":".$question->max[$key]; original line for min/max
5e7856af 363 $answer->response = $question->feedback[$key];
364 if (!$answer->id = insert_record("lesson_answers", $answer)) {
365 $result->error = "Could not insert numerical quiz answer!";
366 return $result;
367 }
368
369 $answers[] = $answer->id;
370 if ($question->fraction[$key] > $maxfraction) {
371 $maxfraction = $question->fraction[$key];
372 }
373 }
374 }
375
376 /// Perform sanity checks on fractional grades
377 if ($maxfraction != 1) {
378 $maxfraction = $maxfraction * 100;
379 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
380 return $result;
381 }
382 break;
383
384
385 case LESSON_TRUEFALSE:
386
387 // the truth
388 $answer->lessonid = $question->lessonid;
389 $answer->pageid = $question->id;
390 $answer->timecreated = $timenow;
391 $answer->answer = get_string("true", "quiz");
392 $answer->grade = $question->answer * 100;
393 if ($answer->grade > 50 ) {
394 $answer->jumpto = LESSON_NEXTPAGE;
395 }
396 if (isset($question->feedbacktrue)) {
397 $answer->response = $question->feedbacktrue;
398 }
399 if (!$true->id = insert_record("lesson_answers", $answer)) {
400 $result->error = "Could not insert quiz answer \"true\")!";
401 return $result;
402 }
403
404 // the lie
f7ffb898 405 $answer = new stdClass;
5e7856af 406 $answer->lessonid = $question->lessonid;
407 $answer->pageid = $question->id;
408 $answer->timecreated = $timenow;
409 $answer->answer = get_string("false", "quiz");
410 $answer->grade = (1 - (int)$question->answer) * 100;
411 if ($answer->grade > 50 ) {
412 $answer->jumpto = LESSON_NEXTPAGE;
413 }
414 if (isset($question->feedbackfalse)) {
415 $answer->response = $question->feedbackfalse;
416 }
417 if (!$false->id = insert_record("lesson_answers", $answer)) {
418 $result->error = "Could not insert quiz answer \"false\")!";
419 return $result;
420 }
421
422 break;
423
424
425 case LESSON_MULTICHOICE:
426
427 $totalfraction = 0;
428 $maxfraction = -1;
429
430 $answers = array();
431
432 // Insert all the new answers
433 foreach ($question->answer as $key => $dataanswer) {
434 if ($dataanswer != "") {
f7ffb898 435 $answer = new stdClass;
5e7856af 436 $answer->lessonid = $question->lessonid;
437 $answer->pageid = $question->id;
438 $answer->timecreated = $timenow;
439 $answer->grade = $question->fraction[$key] * 100;
62eda6ea 440 // changed some defaults
ac8e16be 441 /* Original Code
442 if ($answer->grade > 50 ) {
5e7856af 443 $answer->jumpto = LESSON_NEXTPAGE;
444 }
ac8e16be 445 Replaced with: */
446 if ($answer->grade > 50 ) {
447 $answer->jumpto = LESSON_NEXTPAGE;
5e7856af 448 $answer->score = 1;
449 }
ac8e16be 450 // end Replace
5e7856af 451 $answer->answer = $dataanswer;
452 $answer->response = $question->feedback[$key];
453 if (!$answer->id = insert_record("lesson_answers", $answer)) {
454 $result->error = "Could not insert multichoice quiz answer! ";
455 return $result;
456 }
457 // for Sanity checks
458 if ($question->fraction[$key] > 0) {
459 $totalfraction += $question->fraction[$key];
460 }
461 if ($question->fraction[$key] > $maxfraction) {
462 $maxfraction = $question->fraction[$key];
463 }
464 }
465 }
466
467 /// Perform sanity checks on fractional grades
468 if ($question->single) {
469 if ($maxfraction != 1) {
470 $maxfraction = $maxfraction * 100;
471 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
472 return $result;
473 }
474 } else {
475 $totalfraction = round($totalfraction,2);
476 if ($totalfraction != 1) {
477 $totalfraction = $totalfraction * 100;
478 $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction);
479 return $result;
480 }
481 }
482 break;
483
484 case LESSON_MATCHING:
485
486 $subquestions = array();
487
488 $i = 0;
489 // Insert all the new question+answer pairs
490 foreach ($question->subquestions as $key => $questiontext) {
90455bb3 491 $answertext = $question->subanswers[$key];
5e7856af 492 if (!empty($questiontext) and !empty($answertext)) {
f7ffb898 493 $answer = new stdClass;
5e7856af 494 $answer->lessonid = $question->lessonid;
495 $answer->pageid = $question->id;
496 $answer->timecreated = $timenow;
497 $answer->answer = $questiontext;
498 $answer->response = $answertext;
499 if ($i == 0) {
500 // first answer contains the correct answer jump
501 $answer->jumpto = LESSON_NEXTPAGE;
502 }
503 if (!$subquestion->id = insert_record("lesson_answers", $answer)) {
504 $result->error = "Could not insert quiz match subquestion!";
505 return $result;
506 }
507 $subquestions[] = $subquestion->id;
508 $i++;
509 }
510 }
511
512 if (count($subquestions) < 3) {
513 $result->notice = get_string("notenoughsubquestions", "quiz");
514 return $result;
515 }
516
517 break;
518
519
520 case LESSON_RANDOMSAMATCH:
521 $options->question = $question->id;
522 $options->choose = $question->choose;
523 if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) {
524 $options->id = $existing->id;
525 if (!update_record("quiz_randomsamatch", $options)) {
526 $result->error = "Could not update quiz randomsamatch options!";
527 return $result;
528 }
529 } else {
530 if (!insert_record("quiz_randomsamatch", $options)) {
531 $result->error = "Could not insert quiz randomsamatch options!";
532 return $result;
533 }
534 }
535 break;
536
537 case LESSON_MULTIANSWER:
538 if (!$oldmultianswers = get_records("quiz_multianswers", "question", $question->id, "id ASC")) {
539 $oldmultianswers = array();
540 }
541
542 // Insert all the new multi answers
543 foreach ($question->answers as $dataanswer) {
544 if ($oldmultianswer = array_shift($oldmultianswers)) { // Existing answer, so reuse it
545 $multianswer = $oldmultianswer;
546 $multianswer->positionkey = $dataanswer->positionkey;
547 $multianswer->norm = $dataanswer->norm;
548 $multianswer->answertype = $dataanswer->answertype;
549
550 if (! $multianswer->answers = quiz_save_multianswer_alternatives
551 ($question->id, $dataanswer->answertype,
552 $dataanswer->alternatives, $oldmultianswer->answers))
553 {
554 $result->error = "Could not update multianswer alternatives! (id=$multianswer->id)";
555 return $result;
556 }
557 if (!update_record("quiz_multianswers", $multianswer)) {
558 $result->error = "Could not update quiz multianswer! (id=$multianswer->id)";
559 return $result;
560 }
561 } else { // This is a completely new answer
f7ffb898 562 $multianswer = new stdClass;
5e7856af 563 $multianswer->question = $question->id;
564 $multianswer->positionkey = $dataanswer->positionkey;
565 $multianswer->norm = $dataanswer->norm;
566 $multianswer->answertype = $dataanswer->answertype;
567
568 if (! $multianswer->answers = quiz_save_multianswer_alternatives
569 ($question->id, $dataanswer->answertype,
570 $dataanswer->alternatives))
571 {
572 $result->error = "Could not insert multianswer alternatives! (questionid=$question->id)";
573 return $result;
574 }
575 if (!insert_record("quiz_multianswers", $multianswer)) {
576 $result->error = "Could not insert quiz multianswer!";
577 return $result;
578 }
579 }
580 }
581 break;
582
583 case LESSON_RANDOM:
584 break;
585
586 case LESSON_DESCRIPTION:
587 break;
588
589 default:
590 $result->error = "Unsupported question type ($question->qtype)!";
591 return $result;
592 break;
593 }
594 return true;
595}
4b55d2af 596
597/**
598 * Given an array of value, creates a popup menu to be part of a form.
599 *
600 * @param array $options Used to create the popup menu values ( $options["value"]["label"] ).
601 * @param string $name Name of the select form element.
602 * @param string $selected Current value selected in the popup menu.
603 * @param string $nothing If set, used as the first value in the popup menu.
604 * @param string $script OnChange javascript code.
605 * @param string|int $nothingvalue Value of the $nothing parameter.
606 * @param boolean $return False: Print out the popup menu automatically True: Return the popup menu.
607 * @return string May return the popup menu as a string.
608 * @todo replace the use of this function with choose_from_menu in lib/weblib.php
609 **/
610function lesson_choose_from_menu ($options, $name, $selected="", $nothing="choose", $script="", $nothingvalue="0", $return=false) {
5e7856af 611 if ($nothing == "choose") {
612 $nothing = get_string("choose")."...";
613 }
614
615 if ($script) {
616 $javascript = "onChange=\"$script\"";
617 } else {
618 $javascript = "";
619 }
620
62eda6ea 621 $output = "<label for=$name class=hidden-label>$name</label><SELECT id=$name NAME=$name $javascript>\n";
5e7856af 622 if ($nothing) {
623 $output .= " <OPTION VALUE=\"$nothingvalue\"\n";
624 if ($nothingvalue == $selected) {
625 $output .= " SELECTED";
626 }
627 $output .= ">$nothing</OPTION>\n";
628 }
629 if (!empty($options)) {
630 foreach ($options as $value => $label) {
631 $output .= " <OPTION VALUE=\"$value\"";
632 if ($value == $selected) {
633 $output .= " SELECTED";
634 }
ac8e16be 635 // stop zero label being replaced by array index value
5e7856af 636 // if ($label) {
637 // $output .= ">$label</OPTION>\n";
638 // } else {
639 // $output .= ">$value</OPTION>\n";
ac8e16be 640 // }
641 $output .= ">$label</OPTION>\n";
5e7856af 642
643 }
644 }
645 $output .= "</SELECT>\n";
646
647 if ($return) {
648 return $output;
649 } else {
650 echo $output;
651 }
652}
653
4b55d2af 654/**
655 * Determins if a jumpto value is correct or not.
656 *
657 * returns true if jumpto page is (logically) after the pageid page or
658 * if the jumpto value is a special value. Returns false in all other cases.
659 *
660 * @param int $pageid Id of the page from which you are jumping from.
661 * @param int $jumpto The jumpto number.
662 * @return boolean True or false after a series of tests.
663 * @todo Can be optimized to only have to make 1 or 2 database calls instead of 1 foreach page in the lesson
664 **/
5e7856af 665function lesson_iscorrect($pageid, $jumpto) {
5e7856af 666
667 // first test the special values
668 if (!$jumpto) {
669 // same page
670 return false;
671 } elseif ($jumpto == LESSON_NEXTPAGE) {
672 return true;
ac8e16be 673 } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) {
5e7856af 674 return true;
675 } elseif ($jumpto == LESSON_RANDOMPAGE) {
676 return true;
677 } elseif ($jumpto == LESSON_CLUSTERJUMP) {
678 return true;
5e7856af 679 } elseif ($jumpto == LESSON_EOL) {
680 return true;
681 }
682 // we have to run through the pages from pageid looking for jumpid
683 $apageid = get_field("lesson_pages", "nextpageid", "id", $pageid);
684 while (true) {
685 if ($jumpto == $apageid) {
686 return true;
687 }
688 if ($apageid) {
689 $apageid = get_field("lesson_pages", "nextpageid", "id", $apageid);
690 } else {
691 return false;
692 }
693 }
694 return false; // should never be reached
695}
696
4b55d2af 697/**
698 * Checks to see if a page is a branch table or is
699 * a page that is enclosed by a branch table and an end of branch or end of lesson.
700 * May call this function: {@link lesson_is_page_in_branch()}
701 *
702 * @param int $lesson_id Id of the lesson to which the page belongs.
703 * @param int $pageid Id of the page.
704 * @return boolean True or false.
705 * @todo Change $lesson_id param to $lessonid.
706 **/
5e7856af 707function lesson_display_branch_jumps($lesson_id, $pageid) {
ac8e16be 708 if($pageid == 0) {
709 // first page
710 return false;
711 }
712 // get all of the lesson pages
713 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson_id")) {
714 // adding first page
715 return false;
716 }
717
718 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
719 return true;
720 }
721
722 return lesson_is_page_in_branch($lessonpages, $pageid);
5e7856af 723}
724
4b55d2af 725/**
726 * Checks to see if a page is a cluster page or is
727 * a page that is enclosed by a cluster page and an end of cluster or end of lesson
728 * May call this function: {@link lesson_is_page_in_cluster()}
729 *
730 * @param int $lesson_id Id of the lesson to which the page belongs.
731 * @param int $pageid Id of the page.
732 * @return boolean True or false.
733 * @todo Change $lesson_id param to $lessonid.
734 **/
5e7856af 735function lesson_display_cluster_jump($lesson_id, $pageid) {
ac8e16be 736 if($pageid == 0) {
737 // first page
738 return false;
739 }
740 // get all of the lesson pages
741 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson_id")) {
742 // adding first page
743 return false;
744 }
745
746 if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) {
747 return true;
748 }
749
750 return lesson_is_page_in_cluster($lessonpages, $pageid);
5e7856af 751
752}
753
4b55d2af 754/**
755 * Checks to see if a LESSON_CLUSTERJUMP or
756 * a LESSON_UNSEENBRANCHPAGE is used in a lesson.
757 *
758 * This function is only executed when a teacher is
759 * checking the navigation for a lesson.
760 *
06469639 761 * @param int $lesson Id of the lesson that is to be checked.
4b55d2af 762 * @return boolean True or false.
763 **/
06469639 764function lesson_display_teacher_warning($lesson) {
ac8e16be 765 // get all of the lesson answers
766 if (!$lessonanswers = get_records_select("lesson_answers", "lessonid = $lesson")) {
767 // no answers, then not useing cluster or unseen
768 return false;
769 }
770 // just check for the first one that fulfills the requirements
771 foreach ($lessonanswers as $lessonanswer) {
772 if ($lessonanswer->jumpto == LESSON_CLUSTERJUMP || $lessonanswer->jumpto == LESSON_UNSEENBRANCHPAGE) {
773 return true;
774 }
775 }
776
777 // if no answers use either of the two jumps
778 return false;
5e7856af 779}
780
781
4b55d2af 782/**
783 * Interprets LESSON_CLUSTERJUMP jumpto value.
784 *
785 * This will select a page randomly
786 * and the page selected will be inbetween a cluster page and end of cluter or end of lesson
787 * and the page selected will be a page that has not been viewed already
788 * and if any pages are within a branch table or end of branch then only 1 page within
789 * the branch table or end of branch will be randomly selected (sub clustering).
790 *
791 * @param int $lesson Id of the lesson.
792 * @param int $user Id of the user.
793 * @param int $pageid Id of the current page from which we are jumping from.
794 * @return int The id of the next page.
795 * @todo Change $lesson param to $lessonid and $user param to $userid
796 **/
5e7856af 797function lesson_cluster_jump($lesson, $user, $pageid) {
ac8e16be 798 // get the number of retakes
5e7856af 799 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
ac8e16be 800 $retakes = 0;
801 }
802
803 // get all the lesson_attempts aka what the user has seen
804 if ($seen = get_records_select("lesson_attempts", "lessonid = $lesson AND userid = $user AND retry = $retakes", "timeseen DESC")) {
805 foreach ($seen as $value) { // load it into an array that I can more easily use
806 $seenpages[$value->pageid] = $value->pageid;
807 }
808 } else {
809 $seenpages = array();
810 }
811
812 // get the lesson pages
813 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
814 error("Error: could not find records in lesson_pages table");
815 }
816 // find the start of the cluster
817 while ($pageid != 0) { // this condition should not be satisfied... should be a cluster page
818 if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) {
819 break;
820 }
821 $pageid = $lessonpages[$pageid]->prevpageid;
822 }
823
824 $pageid = $lessonpages[$pageid]->nextpageid; // move down from the cluster page
825
826 $clusterpages = array();
827 while (true) { // now load all the pages into the cluster that are not already inside of a branch table.
828 if ($lessonpages[$pageid]->qtype == LESSON_ENDOFCLUSTER) {
829 // store the endofcluster page's jump
830 $exitjump = get_field("lesson_answers", "jumpto", "pageid", $pageid, "lessonid", $lesson);
831 if ($exitjump == LESSON_NEXTPAGE) {
832 $exitjump = $lessonpages[$pageid]->nextpageid;
833 }
834 if ($exitjump == 0) {
835 $exitjump = LESSON_EOL;
836 }
837 break;
838 } elseif (!lesson_is_page_in_branch($lessonpages, $pageid) && $lessonpages[$pageid]->qtype != LESSON_ENDOFBRANCH) {
839 // load page into array when it is not in a branch table and when it is not an endofbranch
840 $clusterpages[] = $lessonpages[$pageid];
841 }
842 if ($lessonpages[$pageid]->nextpageid == 0) {
843 // shouldn't ever get here... should be using endofcluster
844 $exitjump = LESSON_EOL;
845 break;
846 } else {
847 $pageid = $lessonpages[$pageid]->nextpageid;
848 }
849 }
850
851 // filter out the ones we have seen
852 $unseen = array();
853 foreach ($clusterpages as $clusterpage) {
854 if ($clusterpage->qtype == LESSON_BRANCHTABLE) { // if branchtable, check to see if any pages inside have been viewed
855 $branchpages = lesson_pages_in_branch($lessonpages, $clusterpage->id); // get the pages in the branchtable
856 $flag = true;
857 foreach ($branchpages as $branchpage) {
858 if (array_key_exists($branchpage->id, $seenpages)) { // check if any of the pages have been viewed
859 $flag = false;
860 }
861 }
862 if ($flag && count($branchpages) > 0) {
863 // add branch table
864 $unseen[] = $clusterpage;
865 }
866 } else {
867 // add any other type of page that has not already been viewed
868 if (!array_key_exists($clusterpage->id, $seenpages)) {
869 $unseen[] = $clusterpage;
870 }
871 }
872 }
873
874 if (count($unseen) > 0) { // it does not contain elements, then use exitjump, otherwise find out next page/branch
875 $nextpage = $unseen[rand(0, count($unseen)-1)];
876 } else {
877 return $exitjump; // seen all there is to see, leave the cluster
878 }
879
880 if ($nextpage->qtype == LESSON_BRANCHTABLE) { // if branch table, then pick a random page inside of it
881 $branchpages = lesson_pages_in_branch($lessonpages, $nextpage->id);
882 return $branchpages[rand(0, count($branchpages)-1)]->id;
883 } else { // otherwise, return the page's id
884 return $nextpage->id;
885 }
5e7856af 886}
887
4b55d2af 888/**
889 * Returns pages that are within a branch table and another branch table, end of branch or end of lesson
890 *
891 * @param array $lessonpages An array of lesson page objects.
892 * @param int $branchid The id of the branch table that we would like the containing pages for.
893 * @return array An array of lesson page objects.
894 **/
5e7856af 895function lesson_pages_in_branch($lessonpages, $branchid) {
ac8e16be 896 $pageid = $lessonpages[$branchid]->nextpageid; // move to the first page after the branch table
897 $pagesinbranch = array();
898
899 while (true) {
900 if ($pageid == 0) { // EOL
901 break;
902 } elseif ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
903 break;
904 } elseif ($lessonpages[$pageid]->qtype == LESSON_ENDOFBRANCH) {
905 break;
906 }
907 $pagesinbranch[] = $lessonpages[$pageid];
908 $pageid = $lessonpages[$pageid]->nextpageid;
909 }
910
911 return $pagesinbranch;
5e7856af 912}
913
4b55d2af 914/**
915 * Interprets the LESSON_UNSEENBRANCHPAGE jump.
916 *
917 * will return the pageid of a random unseen page that is within a branch
918 *
919 * @see lesson_pages_in_branch()
920 * @param int $lesson Id of the lesson.
921 * @param int $user Id of the user.
922 * @param int $pageid Id of the page from which we are jumping.
923 * @return int Id of the next page.
924 * @todo Change params $lesson to $lessonid and $user to $userid.
925 **/
5e7856af 926function lesson_unseen_question_jump($lesson, $user, $pageid) {
ac8e16be 927 // get the number of retakes
5e7856af 928 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
ac8e16be 929 $retakes = 0;
930 }
931
932 // get all the lesson_attempts aka what the user has seen
933 if ($viewedpages = get_records_select("lesson_attempts", "lessonid = $lesson AND userid = $user AND retry = $retakes", "timeseen DESC")) {
934 foreach($viewedpages as $viewed) {
935 $seenpages[] = $viewed->pageid;
936 }
937 } else {
938 $seenpages = array();
939 }
940
941 // get the lesson pages
942 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
943 error("Error: could not find records in lesson_pages table");
944 }
945
946 if ($pageid == LESSON_UNSEENBRANCHPAGE) { // this only happens when a student leaves in the middle of an unseen question within a branch series
947 $pageid = $seenpages[0]; // just change the pageid to the last page viewed inside the branch table
948 }
949
950 // go up the pages till branch table
951 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
952 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
953 break;
954 }
955 $pageid = $lessonpages[$pageid]->prevpageid;
956 }
957
958 $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid);
959
960 // this foreach loop stores all the pages that are within the branch table but are not in the $seenpages array
961 $unseen = array();
962 foreach($pagesinbranch as $page) {
963 if (!in_array($page->id, $seenpages)) {
964 $unseen[] = $page->id;
965 }
966 }
967
968 if(count($unseen) == 0) {
969 if(isset($pagesinbranch)) {
970 $temp = end($pagesinbranch);
971 $nextpage = $temp->nextpageid; // they have seen all the pages in the branch, so go to EOB/next branch table/EOL
972 } else {
973 // there are no pages inside the branch, so return the next page
974 $nextpage = $lessonpages[$pageid]->nextpageid;
975 }
976 if ($nextpage == 0) {
977 return LESSON_EOL;
978 } else {
979 return $nextpage;
980 }
981 } else {
982 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page
983 }
5e7856af 984}
985
4b55d2af 986/**
987 * Handles the unseen branch table jump.
988 *
989 * @param int $lesson Lesson id.
990 * @param int $user User id.
991 * @return int Will return the page id of a branch table or end of lesson
992 * @todo Change $lesson param to $lessonid and change $user param to $userid.
993 **/
5e7856af 994function lesson_unseen_branch_jump($lesson, $user) {
5e7856af 995 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
ac8e16be 996 $retakes = 0;
997 }
998
999 if (!$seenbranches = get_records_select("lesson_branch", "lessonid = $lesson AND userid = $user AND retry = $retakes",
1000 "timeseen DESC")) {
1001 error("Error: could not find records in lesson_branch table");
1002 }
1003
1004 // get the lesson pages
1005 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
1006 error("Error: could not find records in lesson_pages table");
1007 }
1008
1009 // this loads all the viewed branch tables into $seen untill it finds the branch table with the flag
1010 // which is the branch table that starts the unseenbranch function
1011 $seen = array();
1012 foreach ($seenbranches as $seenbranch) {
1013 if (!$seenbranch->flag) {
1014 $seen[$seenbranch->pageid] = $seenbranch->pageid;
1015 } else {
1016 $start = $seenbranch->pageid;
1017 break;
1018 }
1019 }
1020 // this function searches through the lesson pages to find all the branch tables
1021 // that follow the flagged branch table
1022 $pageid = $lessonpages[$start]->nextpageid; // move down from the flagged branch table
1023 while ($pageid != 0) { // grab all of the branch table till eol
1024 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
1025 $branchtables[] = $lessonpages[$pageid]->id;
1026 }
1027 $pageid = $lessonpages[$pageid]->nextpageid;
1028 }
1029 $unseen = array();
1030 foreach ($branchtables as $branchtable) {
1031 // load all of the unseen branch tables into unseen
1032 if (!array_key_exists($branchtable, $seen)) {
1033 $unseen[] = $branchtable;
1034 }
1035 }
1036 if (count($unseen) > 0) {
1037 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page
1038 } else {
1039 return LESSON_EOL; // has viewed all of the branch tables
1040 }
5e7856af 1041}
1042
4b55d2af 1043/**
1044 * Handles the random jump between a branch table and end of branch or end of lesson (LESSON_RANDOMPAGE).
1045 *
1046 * @param int $lesson Lesson id.
1047 * @param int $pageid The id of the page that we are jumping from (?)
1048 * @return int The pageid of a random page that is within a branch table
1049 * @todo Change $lesson param to $lessonid.
1050 **/
5e7856af 1051function lesson_random_question_jump($lesson, $pageid) {
ac8e16be 1052 // get the lesson pages
1053 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
1054 error("Error: could not find records in lesson_pages table");
1055 }
1056
1057 // go up the pages till branch table
1058 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
1059
1060 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
1061 break;
1062 }
1063 $pageid = $lessonpages[$pageid]->prevpageid;
1064 }
1065
1066 // get the pages within the branch
1067 $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid);
1068
1069 if(count($pagesinbranch) == 0) {
1070 // there are no pages inside the branch, so return the next page
1071 return $lessonpages[$pageid]->nextpageid;
1072 } else {
1073 return $pagesinbranch[rand(0, count($pagesinbranch)-1)]->id; // returns a random page id for the next page
1074 }
5e7856af 1075}
1076
4b55d2af 1077/**
1078 * Check to see if a page is below a branch table (logically).
1079 *
1080 * Will return true if a branch table is found logically above the page.
1081 * Will return false if an end of branch, cluster or the beginning
1082 * of the lesson is found before a branch table.
1083 *
1084 * @param array $pages An array of lesson page objects.
1085 * @param int $pageid Id of the page for testing.
1086 * @return boolean
1087 */
5e7856af 1088function lesson_is_page_in_branch($pages, $pageid) {
ac8e16be 1089 $pageid = $pages[$pageid]->prevpageid; // move up one
1090
1091 // go up the pages till branch table
1092 while (true) {
1093 if ($pageid == 0) { // ran into the beginning of the lesson
1094 return false;
1095 } elseif ($pages[$pageid]->qtype == LESSON_ENDOFBRANCH) { // ran into the end of another branch table
1096 return false;
1097 } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // do not look beyond a cluster
1098 return false;
1099 } elseif ($pages[$pageid]->qtype == LESSON_BRANCHTABLE) { // hit a branch table
1100 return true;
1101 }
1102 $pageid = $pages[$pageid]->prevpageid;
1103 }
5e7856af 1104
1105}
1106
4b55d2af 1107/**
1108 * Check to see if a page is below a cluster page (logically).
1109 *
1110 * Will return true if a cluster is found logically above the page.
1111 * Will return false if an end of cluster or the beginning
1112 * of the lesson is found before a cluster page.
1113 *
1114 * @param array $pages An array of lesson page objects.
1115 * @param int $pageid Id of the page for testing.
1116 * @return boolean
1117 */
5e7856af 1118function lesson_is_page_in_cluster($pages, $pageid) {
ac8e16be 1119 $pageid = $pages[$pageid]->prevpageid; // move up one
1120
1121 // go up the pages till branch table
1122 while (true) {
1123 if ($pageid == 0) { // ran into the beginning of the lesson
1124 return false;
1125 } elseif ($pages[$pageid]->qtype == LESSON_ENDOFCLUSTER) { // ran into the end of another branch table
1126 return false;
1127 } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // hit a branch table
1128 return true;
1129 }
1130 $pageid = $pages[$pageid]->prevpageid;
1131 }
5e7856af 1132}
1133
4b55d2af 1134/**
1135 * Prints the contents for the left menu
1136 *
1137 * Runs through all of the lesson pages and calls {@link lesson_print_tree_link_menu()}
1138 * to print out the link.
1139 *
1140 * @see lesson_print_tree_link_menu()
1141 * @param int $lessonid Lesson id.
1142 * @param int $pageid Page id of the first page of the lesson.
1143 * @param int $id The cmid of the lesson.
1144 * @param boolean $showpages An optional paramater to show question pages as well as branch tables in the left menu (NYI)
1145 * @todo change $id param to $cmid. Finnish implementing the $showpages feature.
1146 * Not necessary to pass $pageid, we can find that out in the function.
1147 * Also, no real need for {@link lesson_print_tree_link_menu()}. Everything can be handled in this function.
1148 */
b9869082 1149function lesson_print_tree_menu($lessonid, $pageid, $id, $showpages=false) {
4b55d2af 1150 if (!$pages = get_records_select("lesson_pages", "lessonid = $lessonid")) {
ac8e16be 1151 error("Error: could not find lesson pages");
1152 }
d6941aff 1153 echo '<ul>';
ac8e16be 1154 while ($pageid != 0) {
1155 lesson_print_tree_link_menu($pages[$pageid], $id, true);
1156 $pageid = $pages[$pageid]->nextpageid;
1157 }
d6941aff 1158 echo '</ul>';
5e7856af 1159}
1160
4b55d2af 1161/**
1162 * Prints the actual link for the left menu
1163 *
1164 * Only prints branch tables that have display set to on.
1165 *
1166 * @param object $page Lesson page object.
1167 * @param int $id The cmid of the lesson.
1168 * @param boolean $showpages An optional paramater to show question pages as well as branch tables in the left menu (NYI)
1169 * @todo change $id param to $cmid. Finnish implementing the $showpages feature.
1170 */
b9869082 1171function lesson_print_tree_link_menu($page, $id, $showpages=false) {
ac8e16be 1172 if ($page->qtype == LESSON_BRANCHTABLE && !$page->display) {
1173 return false;
1174 } elseif ($page->qtype != LESSON_BRANCHTABLE) {
1175 return false;
1176 }
1177
1178 /*elseif ($page->qtype != LESSON_BRANCHTABLE && !$showpages) {
1179 return false;
1180 } elseif (!in_array($page->qtype, $LESSON_QUESTION_TYPE)) {
1181 return false;
1182 }*/
1183
1184 // set up some variables NoticeFix changed whole function
1185 $output = "";
d6941aff 1186 $class = ' class="leftmenu_not_selected_link" ';
ac8e16be 1187
97d2756c 1188 if($page->id == optional_param('pageid', 0, PARAM_INT)) {
1189 $class = ' class="leftmenu_selected_link" ';
1190 }
ac8e16be 1191
d6941aff 1192 $output .= '<li>';
ac8e16be 1193
d6941aff 1194 $output .= "<a $class href=\"view.php?id=$id&amp;action=navigation&amp;pageid=$page->id\">".format_string($page->title,true)."</a>\n";
1195
1196 $output .= "</li>";
5e7856af 1197
d6941aff 1198 echo $output;
5e7856af 1199}
1200
4b55d2af 1201/**
1202 * Prints out the tree view list.
1203 *
1204 * Each page in the lesson is printed out as a link. If the page is a branch table
1205 * or an end of branch then the link color changes and the answer jumps are also printed
1206 * alongside the links. Also, the editing buttons (move, update, delete) are printed
1207 * next to the links.
1208 *
1209 * @uses $USER
a1d0b3eb 1210 * @uses $CFG
4b55d2af 1211 * @param int $pageid Page id of the first page of the lesson.
a1d0b3eb 1212 * @param object $lesson Object of the current lesson.
4b55d2af 1213 * @param int $cmid The course module id of the lesson.
1214 * @param string $pixpath Path to the pictures.
a1d0b3eb 1215 * @todo $pageid does not need to be passed. Can be found in the function.
97d2756c 1216 * This function is only called once. It should be removed and the code inside it moved to view.php
4b55d2af 1217 */
a1d0b3eb 1218function lesson_print_tree($pageid, $lesson, $cmid) {
1219 global $USER, $CFG;
ac8e16be 1220
a1d0b3eb 1221 if(!$pages = get_records_select("lesson_pages", "lessonid = $lesson->id")) {
ac8e16be 1222 error("Error: could not find lesson pages");
1223 }
1224 echo "<table>";
1225 while ($pageid != 0) {
1226 echo "<tr><td>";
1227 if(($pages[$pageid]->qtype != LESSON_BRANCHTABLE) && ($pages[$pageid]->qtype != LESSON_ENDOFBRANCH)) {
68dfc4de 1228 $output = "<a style='color:#DF041E;' href=\"view.php?id=$cmid&display=".$pages[$pageid]->id."\">".format_string($pages[$pageid]->title,true)."</a>\n";
ac8e16be 1229 } else {
68dfc4de 1230 $output = "<a href=\"view.php?id=$cmid&display=".$pages[$pageid]->id."\">".format_string($pages[$pageid]->title,true)."</a>\n";
ac8e16be 1231
a1d0b3eb 1232 if($answers = get_records_select("lesson_answers", "lessonid = $lesson->id and pageid = $pageid")) {
ac8e16be 1233 $output .= "Jumps to: ";
1234 $end = end($answers);
1235 foreach ($answers as $answer) {
1236 if ($answer->jumpto == 0) {
1237 $output .= get_string("thispage", "lesson");
1238 } elseif ($answer->jumpto == LESSON_NEXTPAGE) {
1239 $output .= get_string("nextpage", "lesson");
1240 } elseif ($answer->jumpto == LESSON_EOL) {
1241 $output .= get_string("endoflesson", "lesson");
1242 } elseif ($answer->jumpto == LESSON_UNSEENBRANCHPAGE) {
1243 $output .= get_string("unseenpageinbranch", "lesson");
1244 } elseif ($answer->jumpto == LESSON_PREVIOUSPAGE) {
1245 $output .= get_string("previouspage", "lesson");
1246 } elseif ($answer->jumpto == LESSON_RANDOMPAGE) {
1247 $output .= get_string("randompageinbranch", "lesson");
1248 } elseif ($answer->jumpto == LESSON_RANDOMBRANCH) {
1249 $output .= get_string("randombranch", "lesson");
1250 } elseif ($answer->jumpto == LESSON_CLUSTERJUMP) {
1251 $output .= get_string("clusterjump", "lesson");
1252 } else {
68dfc4de 1253 $output .= format_string($pages[$answer->jumpto]->title);
ac8e16be 1254 }
1255 if ($answer->id != $end->id) {
1256 $output .= ", ";
1257 }
1258 }
1259 }
1260 }
1261
1262 echo $output;
a1d0b3eb 1263 if (isteacheredit($lesson->course)) {
1264 if (count($pages) > 1) {
1265 echo "<a title=\"move\" href=\"lesson.php?id=$cmid&action=move&pageid=".$pages[$pageid]->id."\">\n".
1266 "<img src=\"$CFG->pixpath/t/move.gif\" hspace=\"2\" height=11 width=11 alt=\"move\" border=0></a>\n";
1267 }
1268 echo "<a title=\"update\" href=\"lesson.php?id=$cmid&amp;action=editpage&amp;pageid=".$pages[$pageid]->id."\">\n".
1269 "<img src=\"$CFG->pixpath/t/edit.gif\" hspace=\"2\" height=11 width=11 alt=\"edit\" border=0></a>\n".
1270 "<a title=\"delete\" href=\"lesson.php?id=$cmid&amp;sesskey=".$USER->sesskey."&amp;action=confirmdelete&amp;pageid=".$pages[$pageid]->id."\">\n".
1271 "<img src=\"$CFG->pixpath/t/delete.gif\" hspace=\"2\" height=11 width=11 alt=\"delete\" border=0></a>\n";
ac8e16be 1272 }
ac8e16be 1273 echo "</tr></td>";
1274 $pageid = $pages[$pageid]->nextpageid;
1275 }
1276 echo "</table>";
5e7856af 1277}
1278
4b55d2af 1279/**
1280 * Calculates a user's grade for a lesson.
1281 *
4b55d2af 1282 * @param object $lesson The lesson that the user is taking.
4b55d2af 1283 * @param int $retries The attempt number.
88427c07 1284 * @param int $userid Id of the user (optinal, default current user).
1285 * @return object { nquestions => number of questions answered
1286 attempts => number of question attempts
1287 total => max points possible
1288 earned => points earned by student
1289 grade => calculated percentage grade
1290 nmanual => number of manually graded questions
1291 manualpoints => point value for manually graded questions }
4b55d2af 1292 */
88427c07 1293function lesson_grade($lesson, $ntries, $userid = 0) {
1294 global $USER;
ac8e16be 1295
88427c07 1296 if (empty($userid)) {
1297 $userid = $USER->id;
1298 }
1299
1300 // Zero out everything
1301 $ncorrect = 0;
1302 $nviewed = 0;
1303 $score = 0;
1304 $nmanual = 0;
1305 $manualpoints = 0;
1306 $thegrade = 0;
1307 $nquestions = 0;
1308 $total = 0;
1309 $earned = 0;
1310
1311 if ($useranswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
1312 userid = $userid AND retry = $ntries", "timeseen")) {
1313 // group each try with its page
1314 $attemptset = array();
1315 foreach ($useranswers as $useranswer) {
1316 $attemptset[$useranswer->pageid][] = $useranswer;
ac8e16be 1317 }
88427c07 1318
1319 // Drop all attempts that go beyond max attempts for the lesson
1320 foreach ($attemptset as $key => $set) {
1321 $attemptset[$key] = array_slice($set, 0, $lesson->maxattempts);
1322 }
1323
1324 $pageids = implode(",", array_keys($attemptset));
1325
1326 // get only the pages and their answers that the user answered
1327 $pages = get_records_select("lesson_pages", "lessonid = $lesson->id AND id IN($pageids)");
1328 $answers = get_records_select("lesson_answers", "lessonid = $lesson->id AND pageid IN($pageids)");
1329
1330 // Number of pages answered
1331 $nquestions = count($pages);
1332
1333 foreach ($attemptset as $attempts) {
1334 if ($lesson->custom) {
1335 $attempt = end($attempts);
1336 // If essay question, handle it, otherwise add to score
1337 if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) {
ac8e16be 1338 $essayinfo = unserialize($attempt->useranswer);
88427c07 1339 $earned += $essayinfo->score;
1340 $nmanual++;
1341 $manualpoints += $answers[$attempt->answerid]->score;
ac8e16be 1342 } else {
88427c07 1343 $earned += $answers[$attempt->answerid]->score;
1344 }
1345 } else {
1346 foreach ($attempts as $attempt) {
1347 $earned += $attempt->correct;
1348 }
1349 $attempt = end($attempts); // doesn't matter which one
1350 // If essay question, increase numbers
1351 if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) {
1352 $nmanual++;
1353 $manualpoints++;
ac8e16be 1354 }
1355 }
88427c07 1356 // Number of times answered
1357 $nviewed += count($attempts);
1358 }
1359
1360 if ($lesson->custom) {
ac8e16be 1361 $bestscores = array();
88427c07 1362 // Find the highest possible score per page to get our total
1363 foreach ($answers as $answer) {
46341ab7 1364 if(!isset($bestscores[$answer->pageid])) {
88427c07 1365 $bestscores[$answer->pageid] = $answer->score;
46341ab7 1366 } else if ($bestscores[$answer->pageid] < $answer->score) {
88427c07 1367 $bestscores[$answer->pageid] = $answer->score;
ac8e16be 1368 }
1369 }
88427c07 1370 $total = array_sum($bestscores);
1371 } else {
1372 // Check to make sure the student has answered the minimum questions
1373 if ($lesson->minquestions and $nquestions < $lesson->minquestions) {
1374 // Nope, increase number viewed by the amount of unanswered questions
1375 $total = $nviewed + ($lesson->minquestions - $nquestions);
1376 } else {
1377 $total = $nviewed;
1378 }
ac8e16be 1379 }
88427c07 1380 }
1381
1382 if ($total) { // not zero
1383 $thegrade = round(100 * $earned / $total, 5);
1384 }
1385
1386 // Build the grade information object
1387 $gradeinfo = new stdClass;
1388 $gradeinfo->nquestions = $nquestions;
1389 $gradeinfo->attempts = $nviewed;
1390 $gradeinfo->total = $total;
1391 $gradeinfo->earned = $earned;
1392 $gradeinfo->grade = $thegrade;
1393 $gradeinfo->nmanual = $nmanual;
1394 $gradeinfo->manualpoints = $manualpoints;
1395
1396 return $gradeinfo;
1397}
1398
1399/**
1400 * Prints the on going message to the user.
1401 *
1402 * With custom grading On, displays points
1403 * earned out of total points possible thus far.
1404 * With custom grading Off, displays number of correct
1405 * answers out of total attempted.
1406 *
1407 * @param object $lesson The lesson that the user is taking.
1408 * @return void
1409 **/
1410function lesson_print_ongoing_score($lesson) {
1411 global $USER;
1412
1413 if (isteacher($lesson->course)) {
1414 echo "<p align=\"center\">".get_string('teacherongoingwarning', 'lesson').'</p>';
1415 } else {
1416 $ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
1417 if (isset($USER->modattempts[$lesson->id])) {
1418 $ntries--;
1419 }
1420 $gradeinfo = lesson_grade($lesson, $ntries);
ac8e16be 1421
88427c07 1422 $a = new stdClass;
1423 if ($lesson->custom) {
1424 $a->score = $gradeinfo->earned;
1425 $a->currenthigh = $gradeinfo->total;
1426 print_simple_box(get_string("ongoingcustom", "lesson", $a), "center");
ac8e16be 1427 } else {
88427c07 1428 $a->correct = $gradeinfo->earned;
1429 $a->viewed = $gradeinfo->attempts;
1430 print_simple_box(get_string("ongoingnormal", "lesson", $a), "center");
ac8e16be 1431 }
1432 }
5e7856af 1433}
1434
4b55d2af 1435/**
1436 * Prints tabs for the editing and adding pages. Each tab is a question type.
1437 *
1438 * @param array $qtypes The question types array (may not need to pass this because it is defined in this file)
1439 * @param string $selected Current selected tab
1440 * @param string $link The base href value of the link for the tab
1441 * @param string $onclick Javascript for the tab link
1442 * @return void
1443 */
5e7856af 1444function lesson_qtype_menu($qtypes, $selected="", $link="", $onclick="") {
271fea97 1445 $tabs = array();
1446 $tabrows = array();
1447
9638a1f4 1448 foreach ($qtypes as $qtype => $qtypename) {
271fea97 1449 $tabrows[] = new tabobject($qtype, "$link&amp;qtype=$qtype\" onClick=\"$onclick\"", $qtypename);
ac8e16be 1450 }
271fea97 1451 $tabs[] = $tabrows;
1452 print_tabs($tabs, $selected);
1453 echo "<input type=\"hidden\" name=\"qtype\" value=\"$selected\" /> \n";
9638a1f4 1454
5e7856af 1455}
1456
4b55d2af 1457/**
1458 * Checks to see if the nickname is naughty or not.
1459 *
1460 * @todo Move this to highscores.php
1461 */
5e7856af 1462function lesson_check_nickname($name) {
5e7856af 1463
832b9f82 1464 if (empty($name)) {
ac8e16be 1465 return false;
1466 }
1467
832b9f82 1468 $filterwords = explode(',', get_string('censorbadwords'));
ac8e16be 1469
1470 foreach ($filterwords as $filterword) {
1471 if (strstr($name, $filterword)) {
1472 return false;
1473 }
1474 }
1475 return true;
5e7856af 1476}
57bfe93d 1477
62eda6ea 1478/**
1479 * Prints out a Progress Bar which depicts a user's progress within a lesson.
1480 *
1481 * Currently works best with a linear lesson. Clusters are counted as a single page.
1482 * Also, only viewed branch tables and questions that have been answered correctly count
1483 * toward lesson completion (or progress). Only Students can see the Progress bar as well.
1484 *
1485 * @param object $lesson The lesson that the user is currently taking.
1486 * @param object $course The course that the to which the lesson belongs.
1487 * @return boolean The return is not significant as of yet. Will return true/false.
1488 * @author Mark Nielsen
1489 **/
1490function lesson_print_progress_bar($lesson, $course) {
1491 global $CFG, $USER;
1492
1493 // lesson setting to turn progress bar on or off
1494 if (!$lesson->progressbar) {
1495 return false;
1496 }
1497
1498 // catch teachers
1499 if (isteacher($course->id)) {
1500 notify(get_string('progressbarteacherwarning', 'lesson', $course->teachers));
1501 return false;
1502 }
acab9099 1503 if (!isset($USER->modattempts[$lesson->id])) {
1504 // all of the lesson pages
1505 if (!$pages = get_records('lesson_pages', 'lessonid', $lesson->id)) {
1506 return false;
1507 } else {
1508 foreach ($pages as $page) {
1509 if ($page->prevpageid == 0) {
1510 $pageid = $page->id; // find the first page id
1511 break;
1512 }
62eda6ea 1513 }
1514 }
62eda6ea 1515
acab9099 1516 // current attempt number
1517 if (!$ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id)) {
1518 $ntries = 0; // may not be necessary
1519 }
62eda6ea 1520
acab9099 1521 $viewedpageids = array();
62eda6ea 1522
acab9099 1523 // collect all of the correctly answered questions
1524 if ($viewedpages = get_records_select("lesson_attempts", "lessonid = $lesson->id AND userid = $USER->id AND retry = $ntries AND correct = 1", 'timeseen DESC', 'pageid, id')) {
1525 $viewedpageids = array_keys($viewedpages);
1526 }
1527 // collect all of the branch tables viewed
1528 if ($viewedbranches = get_records_select("lesson_branch", "lessonid = $lesson->id AND userid = $USER->id AND retry = $ntries", 'timeseen DESC', 'pageid, id')) {
1529 $viewedpageids = array_merge($viewedpageids, array_keys($viewedbranches));
1530 }
1531
1532 // Filter out the following pages:
1533 // End of Cluster
1534 // End of Branch
1535 // Pages found inside of Clusters
1536 // Do not filter out Cluster Page(s) because we count a cluster as one.
1537 // By keeping the cluster page, we get our 1
1538 $validpages = array();
1539 while ($pageid != 0) {
1540 if ($pages[$pageid]->qtype == LESSON_CLUSTER) {
1541 $clusterpageid = $pageid; // copy it
1542 $validpages[$clusterpageid] = 1; // add the cluster page as a valid page
1543 $pageid = $pages[$pageid]->nextpageid; // get next page
62eda6ea 1544
acab9099 1545 // now, remove all necessary viewed paged ids from the viewedpageids array.
1546 while ($pages[$pageid]->qtype != LESSON_ENDOFCLUSTER and $pageid != 0) {
1547 if (in_array($pageid, $viewedpageids)) {
1548 unset($viewedpageids[array_search($pageid, $viewedpageids)]); // remove it
1549 // since the user did see one page in the cluster, add the cluster pageid to the viewedpageids
1550 if (!in_array($clusterpageid, $viewedpageids)) {
1551 $viewedpageids[] = $clusterpageid;
1552 }
62eda6ea 1553 }
acab9099 1554 $pageid = $pages[$pageid]->nextpageid;
62eda6ea 1555 }
acab9099 1556 } elseif ($pages[$pageid]->qtype == LESSON_ENDOFCLUSTER or $pages[$pageid]->qtype == LESSON_ENDOFBRANCH) {
1557 // dont count these, just go to next
1558 $pageid = $pages[$pageid]->nextpageid;
1559 } else {
1560 // a counted page
1561 $validpages[$pageid] = 1;
62eda6ea 1562 $pageid = $pages[$pageid]->nextpageid;
1563 }
acab9099 1564 }
62eda6ea 1565
acab9099 1566 // progress calculation as a percent
1567 $progress = round(count($viewedpageids)/count($validpages), 2) * 100;
1568 } else {
1569 $progress = 100;
1570 }
62eda6ea 1571
1572 // print out the Progress Bar. Attempted to put as much as possible in the style sheets.
1573 echo '<div class="progress_bar" align="center">';
1574 echo '<table class="progress_bar_table"><tr>';
1575 if ($progress != 0) { // some browsers do not repsect the 0 width.
1576 echo '<td width="'.$progress.'%" class="progress_bar_completed">';
1577 echo '</td>';
1578 }
1579 echo '<td class="progress_bar_todo">';
1580 echo '<div class="progress_bar_token"></div>';
1581 echo '</td>';
1582 echo '</tr></table>';
1583 echo '</div>';
1584
1585 return true;
1586}
1587
1588/**
1589 * Determines if a user can view the left menu. The determining factor
1590 * is whether a user has a grade greater than or equal to the lesson setting
1591 * of displayleftif
1592 *
1593 * @param object $lesson Lesson object of the current lesson
1594 * @return boolean 0 if the user cannot see, or $lesson->displayleft to keep displayleft unchanged
1595 * @author Mark Nielsen
1596 **/
1597function lesson_displayleftif($lesson) {
1598 global $CFG, $USER;
1599
1600 if (!empty($lesson->displayleftif)) {
1601 // get the current user's max grade for this lesson
1602 if ($maxgrade = get_record_sql('SELECT userid, MAX(grade) AS maxgrade FROM '.$CFG->prefix.'lesson_grades WHERE userid = '.$USER->id.' AND lessonid = '.$lesson->id.' GROUP BY userid')) {
1603 if ($maxgrade->maxgrade < $lesson->displayleftif) {
1604 return 0; // turn off the displayleft
1605 }
1606 } else {
1607 return 0; // no grades
1608 }
1609 }
1610
1611 // if we get to here, keep the original state of displayleft lesson setting
1612 return $lesson->displayleft;
1613}
5e7856af 1614
2a488ba5 1615?>