polished
[moodle.git] / mod / lesson / locallib.php
CommitLineData
5e7856af 1<?php
2/// mnielsen @ CDC
3/// locallib.php is the new lib file for lesson module.
4/// including locallib.php is the same as including the old lib.php
5
6if (!defined("LESSON_UNSEENPAGE")) {
7 define("LESSON_UNSEENPAGE", 1); // Next page -> any page not seen before
8 }
9if (!defined("LESSON_UNANSWEREDPAGE")) {
10 define("LESSON_UNANSWEREDPAGE", 2); // Next page -> any page not answered correctly
11 }
12
13$LESSON_NEXTPAGE_ACTION = array (0 => get_string("normal", "lesson"),
14 LESSON_UNSEENPAGE => get_string("showanunseenpage", "lesson"),
15 LESSON_UNANSWEREDPAGE => get_string("showanunansweredpage", "lesson") );
16
17
18if (!defined("LESSON_NEXTPAGE")) {
19 define("LESSON_NEXTPAGE", -1); // Next page
20 }
21if (!defined("LESSON_EOL")) {
22 define("LESSON_EOL", -9); // End of Lesson
23 }
24/// CDC-FLAG 6/14/04 ///
25if (!defined("LESSON_UNSEENBRANCHPAGE")) {
26 define("LESSON_UNSEENBRANCHPAGE", -50); // Unseen branch page
27 }
28if (!defined("LESSON_PREVIOUSPAGE")) {
29 define("LESSON_PREVIOUSPAGE", -40); // previous page
30 }
31if (!defined("LESSON_RANDOMPAGE")) {
32 define("LESSON_RANDOMPAGE", -60); // random branch page
33 }
34if (!defined("LESSON_RANDOMBRANCH")) {
35 define("LESSON_RANDOMBRANCH", -70); // random branch
36 }
37if (!defined("LESSON_CLUSTERJUMP")) {
38 define("LESSON_CLUSTERJUMP", -80); // random within a cluster
39 }
40/// CDC-FLAG ///
41if (!defined("LESSON_UNDEFINED")) {
42 define("LESSON_UNDEFINED", -99); // undefined
43 }
44
45if (!defined("LESSON_SHORTANSWER")) {
46 define("LESSON_SHORTANSWER", "1");
47}
48if (!defined("LESSON_TRUEFALSE")) {
49 define("LESSON_TRUEFALSE", "2");
50}
b9869082 51if (!defined("LESSON_MULTICHOICE")) { // if you change the value of this (WHICH YOU SHOULDNT) then you need to change it in restorelib.php as well
5e7856af 52 define("LESSON_MULTICHOICE", "3");
53}
54if (!defined("LESSON_RANDOM")) {
55 define("LESSON_RANDOM", "4");
56}
b9869082 57if (!defined("LESSON_MATCHING")) { // if you change the value of this (WHICH YOU SHOULDNT) then you need to change it in restorelib.php as well
58 define("LESSON_MATCHING", "5");
5e7856af 59}
60if (!defined("LESSON_RANDOMSAMATCH")) {
61 define("LESSON_RANDOMSAMATCH", "6");
62}
63if (!defined("LESSON_DESCRIPTION")) {
64 define("LESSON_DESCRIPTION", "7");
65}
66if (!defined("LESSON_NUMERICAL")) {
67 define("LESSON_NUMERICAL", "8");
68}
69if (!defined("LESSON_MULTIANSWER")) {
70 define("LESSON_MULTIANSWER", "9");
71}
72/// CDC-FLAG /// 6/16/04
73if (!defined("LESSON_ESSAY")) {
74 define("LESSON_ESSAY", "10");
75}
76if (!defined("LESSON_CLUSTER")) {
77 define("LESSON_CLUSTER", "30");
78}
79if (!defined("LESSON_ENDOFCLUSTER")) {
80 define("LESSON_ENDOFCLUSTER", "31");
81}
82/// CDC-FLAG ///
83
84$LESSON_QUESTION_TYPE = array ( LESSON_MULTICHOICE => get_string("multichoice", "quiz"),
85 LESSON_TRUEFALSE => get_string("truefalse", "quiz"),
86 LESSON_SHORTANSWER => get_string("shortanswer", "quiz"),
87 LESSON_NUMERICAL => get_string("numerical", "quiz"),
88 LESSON_MATCHING => get_string("match", "quiz"),
89 LESSON_ESSAY => get_string("essay", "lesson") /// CDC-FLAG 6/16/04
90// LESSON_DESCRIPTION => get_string("description", "quiz"),
91// LESSON_RANDOM => get_string("random", "quiz"),
92// LESSON_RANDOMSAMATCH => get_string("randomsamatch", "quiz"),
93// LESSON_MULTIANSWER => get_string("multianswer", "quiz"),
94 );
95
96if (!defined("LESSON_BRANCHTABLE")) {
97 define("LESSON_BRANCHTABLE", "20");
98}
99if (!defined("LESSON_ENDOFBRANCH")) {
100 define("LESSON_ENDOFBRANCH", "21");
101}
102
103if (!defined("LESSON_ANSWER_EDITOR")) {
104 define("LESSON_ANSWER_EDITOR", "1");
105}
106if (!defined("LESSON_RESPONSE_EDITOR")) {
107 define("LESSON_RESPONSE_EDITOR", "2");
108}
109
110//////////////////////////////////////////////////////////////////////////////////////
111/// Any other lesson functions go here. Each of them must have a name that
112/// starts with lesson_
113
114/*******************************************************************/
115function lesson_save_question_options($question) {
116/// Given some question info and some data about the the answers
117/// this function parses, organises and saves the question
118/// This is only used when IMPORTING questions and is only called
119/// from format.php
120/// Lifted from mod/quiz/lib.php -
121/// 1. all reference to oldanswers removed
122/// 2. all reference to quiz_multichoice table removed
123/// 3. In SHORTANSWER questions usecase is store in the qoption field
124/// 4. In NUMERIC questions store the range as two answers
125/// 5. TRUEFALSE options are ignored
126/// 6. For MULTICHOICE questions with more than one answer the qoption field is true
127///
128/// Returns $result->error or $result->notice
129
130 $timenow = time();
131 switch ($question->qtype) {
132 case LESSON_SHORTANSWER:
133
134 $answers = array();
135 $maxfraction = -1;
136
137 // Insert all the new answers
138 foreach ($question->answer as $key => $dataanswer) {
139 if ($dataanswer != "") {
f7ffb898 140 $answer = new stdClass;
5e7856af 141 $answer->lessonid = $question->lessonid;
142 $answer->pageid = $question->id;
143 if ($question->fraction[$key] >=0.5) {
144 $answer->jumpto = LESSON_NEXTPAGE;
145 }
146 $answer->timecreated = $timenow;
147 $answer->grade = $question->fraction[$key] * 100;
148 $answer->answer = $dataanswer;
149 $answer->feedback = $question->feedback[$key];
150 if (!$answer->id = insert_record("lesson_answers", $answer)) {
151 $result->error = "Could not insert shortanswer quiz answer!";
152 return $result;
153 }
154 $answers[] = $answer->id;
155 if ($question->fraction[$key] > $maxfraction) {
156 $maxfraction = $question->fraction[$key];
157 }
158 }
159 }
160
161
162 /// Perform sanity checks on fractional grades
163 if ($maxfraction != 1) {
164 $maxfraction = $maxfraction * 100;
165 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
166 return $result;
167 }
168 break;
169
170 case LESSON_NUMERICAL: // Note similarities to SHORTANSWER
171
172 $answers = array();
173 $maxfraction = -1;
174
175
176 // for each answer store the pair of min and max values even if they are the same
177 foreach ($question->answer as $key => $dataanswer) {
178 if ($dataanswer != "") {
f7ffb898 179 $answer = new stdClass;
5e7856af 180 $answer->lessonid = $question->lessonid;
181 $answer->pageid = $question->id;
182 $answer->jumpto = LESSON_NEXTPAGE;
183 $answer->timecreated = $timenow;
184 $answer->grade = $question->fraction[$key] * 100;
185 $answer->answer = $question->min[$key].":".$question->max[$key];
186 $answer->response = $question->feedback[$key];
187 if (!$answer->id = insert_record("lesson_answers", $answer)) {
188 $result->error = "Could not insert numerical quiz answer!";
189 return $result;
190 }
191
192 $answers[] = $answer->id;
193 if ($question->fraction[$key] > $maxfraction) {
194 $maxfraction = $question->fraction[$key];
195 }
196 }
197 }
198
199 /// Perform sanity checks on fractional grades
200 if ($maxfraction != 1) {
201 $maxfraction = $maxfraction * 100;
202 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
203 return $result;
204 }
205 break;
206
207
208 case LESSON_TRUEFALSE:
209
210 // the truth
211 $answer->lessonid = $question->lessonid;
212 $answer->pageid = $question->id;
213 $answer->timecreated = $timenow;
214 $answer->answer = get_string("true", "quiz");
215 $answer->grade = $question->answer * 100;
216 if ($answer->grade > 50 ) {
217 $answer->jumpto = LESSON_NEXTPAGE;
218 }
219 if (isset($question->feedbacktrue)) {
220 $answer->response = $question->feedbacktrue;
221 }
222 if (!$true->id = insert_record("lesson_answers", $answer)) {
223 $result->error = "Could not insert quiz answer \"true\")!";
224 return $result;
225 }
226
227 // the lie
f7ffb898 228 $answer = new stdClass;
5e7856af 229 $answer->lessonid = $question->lessonid;
230 $answer->pageid = $question->id;
231 $answer->timecreated = $timenow;
232 $answer->answer = get_string("false", "quiz");
233 $answer->grade = (1 - (int)$question->answer) * 100;
234 if ($answer->grade > 50 ) {
235 $answer->jumpto = LESSON_NEXTPAGE;
236 }
237 if (isset($question->feedbackfalse)) {
238 $answer->response = $question->feedbackfalse;
239 }
240 if (!$false->id = insert_record("lesson_answers", $answer)) {
241 $result->error = "Could not insert quiz answer \"false\")!";
242 return $result;
243 }
244
245 break;
246
247
248 case LESSON_MULTICHOICE:
249
250 $totalfraction = 0;
251 $maxfraction = -1;
252
253 $answers = array();
254
255 // Insert all the new answers
256 foreach ($question->answer as $key => $dataanswer) {
257 if ($dataanswer != "") {
f7ffb898 258 $answer = new stdClass;
5e7856af 259 $answer->lessonid = $question->lessonid;
260 $answer->pageid = $question->id;
261 $answer->timecreated = $timenow;
262 $answer->grade = $question->fraction[$key] * 100;
263 /// CDC-FLAG changed some defaults
264 /* Original Code
265 if ($answer->grade > 50 ) {
266 $answer->jumpto = LESSON_NEXTPAGE;
267 }
268 Replaced with: */
269 if ($answer->grade > 50 ) {
270 $answer->jumpto = LESSON_NEXTPAGE;
271 $answer->score = 1;
272 }
273 // end Replace
274 $answer->answer = $dataanswer;
275 $answer->response = $question->feedback[$key];
276 if (!$answer->id = insert_record("lesson_answers", $answer)) {
277 $result->error = "Could not insert multichoice quiz answer! ";
278 return $result;
279 }
280 // for Sanity checks
281 if ($question->fraction[$key] > 0) {
282 $totalfraction += $question->fraction[$key];
283 }
284 if ($question->fraction[$key] > $maxfraction) {
285 $maxfraction = $question->fraction[$key];
286 }
287 }
288 }
289
290 /// Perform sanity checks on fractional grades
291 if ($question->single) {
292 if ($maxfraction != 1) {
293 $maxfraction = $maxfraction * 100;
294 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
295 return $result;
296 }
297 } else {
298 $totalfraction = round($totalfraction,2);
299 if ($totalfraction != 1) {
300 $totalfraction = $totalfraction * 100;
301 $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction);
302 return $result;
303 }
304 }
305 break;
306
307 case LESSON_MATCHING:
308
309 $subquestions = array();
310
311 $i = 0;
312 // Insert all the new question+answer pairs
313 foreach ($question->subquestions as $key => $questiontext) {
314 $answertext = $question->subanswers[$key]; echo $answertext; echo "<br>"; exit;
315 if (!empty($questiontext) and !empty($answertext)) {
f7ffb898 316 $answer = new stdClass;
5e7856af 317 $answer->lessonid = $question->lessonid;
318 $answer->pageid = $question->id;
319 $answer->timecreated = $timenow;
320 $answer->answer = $questiontext;
321 $answer->response = $answertext;
322 if ($i == 0) {
323 // first answer contains the correct answer jump
324 $answer->jumpto = LESSON_NEXTPAGE;
325 }
326 if (!$subquestion->id = insert_record("lesson_answers", $answer)) {
327 $result->error = "Could not insert quiz match subquestion!";
328 return $result;
329 }
330 $subquestions[] = $subquestion->id;
331 $i++;
332 }
333 }
334
335 if (count($subquestions) < 3) {
336 $result->notice = get_string("notenoughsubquestions", "quiz");
337 return $result;
338 }
339
340 break;
341
342
343 case LESSON_RANDOMSAMATCH:
344 $options->question = $question->id;
345 $options->choose = $question->choose;
346 if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) {
347 $options->id = $existing->id;
348 if (!update_record("quiz_randomsamatch", $options)) {
349 $result->error = "Could not update quiz randomsamatch options!";
350 return $result;
351 }
352 } else {
353 if (!insert_record("quiz_randomsamatch", $options)) {
354 $result->error = "Could not insert quiz randomsamatch options!";
355 return $result;
356 }
357 }
358 break;
359
360 case LESSON_MULTIANSWER:
361 if (!$oldmultianswers = get_records("quiz_multianswers", "question", $question->id, "id ASC")) {
362 $oldmultianswers = array();
363 }
364
365 // Insert all the new multi answers
366 foreach ($question->answers as $dataanswer) {
367 if ($oldmultianswer = array_shift($oldmultianswers)) { // Existing answer, so reuse it
368 $multianswer = $oldmultianswer;
369 $multianswer->positionkey = $dataanswer->positionkey;
370 $multianswer->norm = $dataanswer->norm;
371 $multianswer->answertype = $dataanswer->answertype;
372
373 if (! $multianswer->answers = quiz_save_multianswer_alternatives
374 ($question->id, $dataanswer->answertype,
375 $dataanswer->alternatives, $oldmultianswer->answers))
376 {
377 $result->error = "Could not update multianswer alternatives! (id=$multianswer->id)";
378 return $result;
379 }
380 if (!update_record("quiz_multianswers", $multianswer)) {
381 $result->error = "Could not update quiz multianswer! (id=$multianswer->id)";
382 return $result;
383 }
384 } else { // This is a completely new answer
f7ffb898 385 $multianswer = new stdClass;
5e7856af 386 $multianswer->question = $question->id;
387 $multianswer->positionkey = $dataanswer->positionkey;
388 $multianswer->norm = $dataanswer->norm;
389 $multianswer->answertype = $dataanswer->answertype;
390
391 if (! $multianswer->answers = quiz_save_multianswer_alternatives
392 ($question->id, $dataanswer->answertype,
393 $dataanswer->alternatives))
394 {
395 $result->error = "Could not insert multianswer alternatives! (questionid=$question->id)";
396 return $result;
397 }
398 if (!insert_record("quiz_multianswers", $multianswer)) {
399 $result->error = "Could not insert quiz multianswer!";
400 return $result;
401 }
402 }
403 }
404 break;
405
406 case LESSON_RANDOM:
407 break;
408
409 case LESSON_DESCRIPTION:
410 break;
411
412 default:
413 $result->error = "Unsupported question type ($question->qtype)!";
414 return $result;
415 break;
416 }
417 return true;
418}
419/*******************************************************************/
420function lesson_choose_from_menu ($options, $name, $selected="", $nothing="choose", $script="", $nothingvalue="0", $return=false) {
421/// Given an array of value, creates a popup menu to be part of a form
422/// $options["value"]["label"]
423
424 if ($nothing == "choose") {
425 $nothing = get_string("choose")."...";
426 }
427
428 if ($script) {
429 $javascript = "onChange=\"$script\"";
430 } else {
431 $javascript = "";
432 }
433
434 $output = "<label for=$name class=hidden-label>$name</label><SELECT id=$name NAME=$name $javascript>\n"; //CDC hidden label added.
435 if ($nothing) {
436 $output .= " <OPTION VALUE=\"$nothingvalue\"\n";
437 if ($nothingvalue == $selected) {
438 $output .= " SELECTED";
439 }
440 $output .= ">$nothing</OPTION>\n";
441 }
442 if (!empty($options)) {
443 foreach ($options as $value => $label) {
444 $output .= " <OPTION VALUE=\"$value\"";
445 if ($value == $selected) {
446 $output .= " SELECTED";
447 }
448 // stop zero label being replaced by array index value
449 // if ($label) {
450 // $output .= ">$label</OPTION>\n";
451 // } else {
452 // $output .= ">$value</OPTION>\n";
453 // }
454 $output .= ">$label</OPTION>\n";
455
456 }
457 }
458 $output .= "</SELECT>\n";
459
460 if ($return) {
461 return $output;
462 } else {
463 echo $output;
464 }
465}
466
467/*******************************************************************/
468function lesson_iscorrect($pageid, $jumpto) {
469 // returns true is jumpto page is (logically) after the pageid page, other returns false
470
471 // first test the special values
472 if (!$jumpto) {
473 // same page
474 return false;
475 } elseif ($jumpto == LESSON_NEXTPAGE) {
476 return true;
477 /// CDC-FLAG 6/21/04 ///
478 } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) {
479 return true;
480 } elseif ($jumpto == LESSON_RANDOMPAGE) {
481 return true;
482 } elseif ($jumpto == LESSON_CLUSTERJUMP) {
483 return true;
484 /// CDC-FLAG ///
485 } elseif ($jumpto == LESSON_EOL) {
486 return true;
487 }
488 // we have to run through the pages from pageid looking for jumpid
489 $apageid = get_field("lesson_pages", "nextpageid", "id", $pageid);
490 while (true) {
491 if ($jumpto == $apageid) {
492 return true;
493 }
494 if ($apageid) {
495 $apageid = get_field("lesson_pages", "nextpageid", "id", $apageid);
496 } else {
497 return false;
498 }
499 }
500 return false; // should never be reached
501}
502
503/// CDC-FLAG ///
504/*******************************************************************/
505function lesson_display_branch_jumps($lesson_id, $pageid) {
506// this fucntion checks to see if a page is a branch or is
507// a page that is enclosed by a branch table and an endofbranch/eol
508
509 // NoticeFix ... this may cause problems... not sure
510 if($pageid == 0) {
511 // first page
512 return false;
513 }
514 // get all of the lesson pages
515 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson_id")) {
516 // adding first page
517 return false;
518 }
519
520 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
521 return true;
522 }
523
524 return lesson_is_page_in_branch($lessonpages, $pageid);
525}
526
527/*******************************************************************/
528function lesson_display_cluster_jump($lesson_id, $pageid) {
529// this fucntion checks to see if a page is a cluster page or is
530// a page that is enclosed by a cluster page and an endofcluster/eol
531
532 // NoticeFix ... this may cause problems... not sure
533 if($pageid == 0) {
534 // first page
535 return false;
536 }
537 // get all of the lesson pages
538 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson_id")) {
539 // adding first page
540 return false;
541 }
542
543 if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) {
544 return true;
545 }
546
547 return lesson_is_page_in_cluster($lessonpages, $pageid);
548
549}
550
551// 6/21/04
552/*******************************************************************/
553function execute_teacherwarning($lesson) {
554// this function checks to see if a LESSON_CLUSTERJUMP or
555// a LESSON_UNSEENBRANCHPAGE is used in a lesson.
556// This function is only executed when a teacher is
557// checking the navigation for a lesson.
558
559 // get all of the lesson answers
560 if (!$lessonanswers = get_records_select("lesson_answers", "lessonid = $lesson")) {
561 // no answers, then not useing cluster or unseen
562 return false;
563 }
564 // just check for the first one that fulfills the requirements
565 foreach ($lessonanswers as $lessonanswer) {
566 if ($lessonanswer->jumpto == LESSON_CLUSTERJUMP || $lessonanswer->jumpto == LESSON_UNSEENBRANCHPAGE) {
567 return true;
568 }
569 }
570
571 // if no answers use either of the two jumps
572 return false;
573}
574
575
576// 6/18/04
577/*******************************************************************/
578function lesson_cluster_jump($lesson, $user, $pageid) {
579// this fucntion interprets LESSON_CLUSTERJUMP
580// it will select a page randomly
581// and the page selected will be inbetween a cluster page and endofcluter/eol
582// and the page selected will be a page that has not been viewed already
583// and if any pages are within a branchtable/endofbranch then only 1 page within
584// the branchtable/endofbranch will be randomly selected (sub clustering)
585
586 // get the number of retakes
587 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
588 $retakes = 0;
589 }
590
591 // get all the lesson_attempts aka what the user has seen
592 if ($seen = get_records_select("lesson_attempts", "lessonid = $lesson AND userid = $user AND retry = $retakes", "timeseen DESC")) {
593 foreach ($seen as $value) { // load it into an array that I can more easily use
594 $seenpages[$value->pageid] = $value->pageid;
595 }
596 } else {
597 $seenpages = array();
598 }
599
600 // get the lesson pages
601 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
602 error("Error: could not find records in lesson_pages table");
603 }
604 // find the start of the cluster
605 while ($pageid != 0) { // this condition should not be satisfied... should be a cluster page
606 if ($lessonpages[$pageid]->qtype == LESSON_CLUSTER) {
607 break;
608 }
609 $pageid = $lessonpages[$pageid]->prevpageid;
610 }
611
612 $pageid = $lessonpages[$pageid]->nextpageid; // move down from the cluster page
f7ffb898 613
614 $clusterpages = array();
5e7856af 615 while (true) { // now load all the pages into the cluster that are not already inside of a branch table.
616 if ($lessonpages[$pageid]->qtype == LESSON_ENDOFCLUSTER) {
617 // store the endofcluster page's jump
c7321886 618 $exitjump = get_field("lesson_answers", "jumpto", "pageid", $pageid, "lessonid", $lesson);
5e7856af 619 if ($exitjump == LESSON_NEXTPAGE) {
909e6c79 620 $exitjump = $lessonpages[$pageid]->nextpageid;
5e7856af 621 }
622 if ($exitjump == 0) {
623 $exitjump = LESSON_EOL;
624 }
625 break;
626 } elseif (!lesson_is_page_in_branch($lessonpages, $pageid) && $lessonpages[$pageid]->qtype != LESSON_ENDOFBRANCH) {
627 // load page into array when it is not in a branch table and when it is not an endofbranch
628 $clusterpages[] = $lessonpages[$pageid];
629 }
630 if ($lessonpages[$pageid]->nextpageid == 0) {
631 // shouldn't ever get here... should be using endofcluster
632 $exitjump = LESSON_EOL;
633 break;
634 } else {
635 $pageid = $lessonpages[$pageid]->nextpageid;
636 }
637 }
638
639 // filter out the ones we have seen
f7ffb898 640 $unseen = array();
5e7856af 641 foreach ($clusterpages as $clusterpage) {
642 if ($clusterpage->qtype == LESSON_BRANCHTABLE) { // if branchtable, check to see if any pages inside have been viewed
643 $branchpages = lesson_pages_in_branch($lessonpages, $clusterpage->id); // get the pages in the branchtable
644 $flag = true;
645 foreach ($branchpages as $branchpage) {
646 if (array_key_exists($branchpage->id, $seenpages)) { // check if any of the pages have been viewed
647 $flag = false;
648 }
649 }
650 if ($flag && count($branchpages) > 0) {
651 // add branch table
652 $unseen[] = $clusterpage;
653 }
654 } else {
655 // add any other type of page that has not already been viewed
656 if (!array_key_exists($clusterpage->id, $seenpages)) {
657 $unseen[] = $clusterpage;
658 }
659 }
660 }
661
f7ffb898 662 if (count($unseen) > 0) { // it does not contain elements, then use exitjump, otherwise find out next page/branch
5e7856af 663 $nextpage = $unseen[rand(0, count($unseen)-1)];
664 } else {
665 return $exitjump; // seen all there is to see, leave the cluster
666 }
667
668 if ($nextpage->qtype == LESSON_BRANCHTABLE) { // if branch table, then pick a random page inside of it
669 $branchpages = lesson_pages_in_branch($lessonpages, $nextpage->id);
670 return $branchpages[rand(0, count($branchpages)-1)]->id;
671 } else { // otherwise, return the page's id
672 return $nextpage->id;
673 }
674}
675
676/*******************************************************************/
677function lesson_pages_in_branch($lessonpages, $branchid) {
678// returns pages that are within a branch
679
680 $pageid = $lessonpages[$branchid]->nextpageid; // move to the first page after the branch table
681 $pagesinbranch = array();
682
683 while (true) {
684 if ($pageid == 0) { // EOL
685 break;
686 } elseif ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
687 break;
688 } elseif ($lessonpages[$pageid]->qtype == LESSON_ENDOFBRANCH) {
689 break;
690 }
691 $pagesinbranch[] = $lessonpages[$pageid];
692 $pageid = $lessonpages[$pageid]->nextpageid;
693 }
694
695 return $pagesinbranch;
696}
697
698/*******************************************************************/
699function lesson_unseen_question_jump($lesson, $user, $pageid) {
700// This function interprets the LESSON_UNSEENBRANCHPAGE jump.
701// will return the pageid of a random unseen page that is within a branch
702
703 // get the number of retakes
704 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
705 $retakes = 0;
706 }
707
708 // get all the lesson_attempts aka what the user has seen
709 if ($viewedpages = get_records_select("lesson_attempts", "lessonid = $lesson AND userid = $user AND retry = $retakes", "timeseen DESC")) {
710 foreach($viewedpages as $viewed) {
711 $seenpages[] = $viewed->pageid;
712 }
713 } else {
714 $seenpages = array();
715 }
716
717 // get the lesson pages
718 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
719 error("Error: could not find records in lesson_pages table");
720 }
721
722 if ($pageid == LESSON_UNSEENBRANCHPAGE) { // this only happens when a student leaves in the middle of an unseen question within a branch series
723 $pageid = $seenpages[0]; // just change the pageid to the last page viewed inside the branch table
724 }
725
726 // go up the pages till branch table
727 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
728 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
729 break;
730 }
731 $pageid = $lessonpages[$pageid]->prevpageid;
732 }
733
734 $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid);
735
736 // this foreach loop stores all the pages that are within the branch table but are not in the $seenpages array
f7ffb898 737 $unseen = array();
5e7856af 738 foreach($pagesinbranch as $page) {
739 if (!in_array($page->id, $seenpages)) {
740 $unseen[] = $page->id;
741 }
742 }
743
f7ffb898 744 if(count($unseen) == 0) {
5e7856af 745 if(isset($pagesinbranch)) {
746 $temp = end($pagesinbranch);
747 $nextpage = $temp->nextpageid; // they have seen all the pages in the branch, so go to EOB/next branch table/EOL
748 } else {
749 // there are no pages inside the branch, so return the next page
750 $nextpage = $lessonpages[$pageid]->nextpageid;
751 }
752 if ($nextpage == 0) {
753 return LESSON_EOL;
754 } else {
755 return $nextpage;
756 }
757 } else {
758 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page
759 }
760}
761
762// 6/15/04
763/*******************************************************************/
764function lesson_unseen_branch_jump($lesson, $user) {
765// This will return a random unseen branch table
766
767 if (!$retakes = count_records("lesson_grades", "lessonid", $lesson, "userid", $user)) {
768 $retakes = 0;
769 }
770
771 if (!$seenbranches = get_records_select("lesson_branch", "lessonid = $lesson AND userid = $user AND retry = $retakes",
772 "timeseen DESC")) {
773 error("Error: could not find records in lesson_branch table");
774 }
775
776 // get the lesson pages
777 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
778 error("Error: could not find records in lesson_pages table");
779 }
780
781 // this loads all the viewed branch tables into $seen untill it finds the branch table with the flag
782 // which is the branch table that starts the unseenbranch function
783 $seen = array();
784 foreach ($seenbranches as $seenbranch) {
785 if (!$seenbranch->flag) {
786 $seen[$seenbranch->pageid] = $seenbranch->pageid;
787 } else {
788 $start = $seenbranch->pageid;
789 break;
790 }
791 }
792 // this function searches through the lesson pages to find all the branch tables
793 // that follow the flagged branch table
794 $pageid = $lessonpages[$start]->nextpageid; // move down from the flagged branch table
795 while ($pageid != 0) { // grab all of the branch table till eol
796 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
797 $branchtables[] = $lessonpages[$pageid]->id;
798 }
799 $pageid = $lessonpages[$pageid]->nextpageid;
800 }
f7ffb898 801 $unseen = array();
5e7856af 802 foreach ($branchtables as $branchtable) {
803 // load all of the unseen branch tables into unseen
804 if (!array_key_exists($branchtable, $seen)) {
805 $unseen[] = $branchtable;
806 }
807 }
f7ffb898 808 if (count($unseen) > 0) {
5e7856af 809 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page
810 } else {
811 return LESSON_EOL; // has viewed all of the branch tables
812 }
813}
814
815/*******************************************************************/
816function lesson_random_question_jump($lesson, $pageid) {
817// This function will return the pageid of a random page
818// that is within a branch table
819
820 // get the lesson pages
821 if (!$lessonpages = get_records_select("lesson_pages", "lessonid = $lesson")) {
822 error("Error: could not find records in lesson_pages table");
823 }
824
825 // go up the pages till branch table
826 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
827
828 if ($lessonpages[$pageid]->qtype == LESSON_BRANCHTABLE) {
829 break;
830 }
831 $pageid = $lessonpages[$pageid]->prevpageid;
832 }
833
834 // get the pages within the branch
835 $pagesinbranch = lesson_pages_in_branch($lessonpages, $pageid);
836
f7ffb898 837 if(count($pagesinbranch) == 0) {
5e7856af 838 // there are no pages inside the branch, so return the next page
839 return $lessonpages[$pageid]->nextpageid;
840 } else {
841 return $pagesinbranch[rand(0, count($pagesinbranch)-1)]->id; // returns a random page id for the next page
842 }
843}
844
845// 6/15/04
846/*******************************************************************/
847function lesson_is_page_in_branch($pages, $pageid) {
848// This function's purpose is to check if a page is within a branch or not
849
850 $pageid = $pages[$pageid]->prevpageid; // move up one
851
852 // go up the pages till branch table
853 while (true) {
854 if ($pageid == 0) { // ran into the beginning of the lesson
855 return false;
856 } elseif ($pages[$pageid]->qtype == LESSON_ENDOFBRANCH) { // ran into the end of another branch table
857 return false;
858 } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // do not look beyond a cluster
859 return false;
860 } elseif ($pages[$pageid]->qtype == LESSON_BRANCHTABLE) { // hit a branch table
861 return true;
862 }
863 $pageid = $pages[$pageid]->prevpageid;
864 }
865
866}
867
868/*******************************************************************/
869function lesson_is_page_in_cluster($pages, $pageid) {
870// This function checks to see if a page is within a cluster or not
871
872 $pageid = $pages[$pageid]->prevpageid; // move up one
873
874 // go up the pages till branch table
875 while (true) {
876 if ($pageid == 0) { // ran into the beginning of the lesson
877 return false;
878 } elseif ($pages[$pageid]->qtype == LESSON_ENDOFCLUSTER) { // ran into the end of another branch table
879 return false;
880 } elseif ($pages[$pageid]->qtype == LESSON_CLUSTER) { // hit a branch table
881 return true;
882 }
883 $pageid = $pages[$pageid]->prevpageid;
884 }
885}
886
887/*******************************************************************/
b9869082 888function lesson_print_tree_menu($lessonid, $pageid, $id, $showpages=false) {
5e7856af 889// prints the contents of the left menu
890
891 if(!$pages = get_records_select("lesson_pages", "lessonid = $lessonid")) {
892 error("Error: could not find lesson pages");
893 }
894 while ($pageid != 0) {
b9869082 895 lesson_print_tree_link_menu($pages[$pageid], $id, true);
5e7856af 896 $pageid = $pages[$pageid]->nextpageid;
897 }
898}
899
900/*******************************************************************/
b9869082 901function lesson_print_tree_link_menu($page, $id, $showpages=false) {
5e7856af 902// prints the actual link for the left menu
903
904 if ($page->qtype == LESSON_BRANCHTABLE && !$page->display) {
905 return false;
b9869082 906 } elseif ($page->qtype != LESSON_BRANCHTABLE) {
907 return false;
5e7856af 908 }
909
b9869082 910 /*elseif ($page->qtype != LESSON_BRANCHTABLE && !$showpages) {
911 return false;
912 } elseif (!in_array($page->qtype, $LESSON_QUESTION_TYPE)) {
913 return false;
914 }*/
915
5e7856af 916 // set up some variables NoticeFix changed whole function
917 $output = "";
918 $close = false;
2a488ba5 919 $link="id=$id&amp;action=navigation&amp;pageid=".$page->id;
5e7856af 920
0733cc00 921 $output = "<li>";
922
324da715 923 if (isset($_REQUEST['pageid'])) {
924 if($page->id == $_REQUEST['pageid']) {
925 $close=true;
0733cc00 926 $output.="<em>";
324da715 927 }
928 }
b9869082 929
0733cc00 930 $output .= "<a href=\"view.php?id=$id&amp;action=navigation&amp;pageid=$page->id\">".$page->title."</a>\n";
b9869082 931
5e7856af 932 if($close) {
0733cc00 933 $output.="</em>";
934 }
935 $output .= "</li>";
936
937
5e7856af 938 echo $output;
939
940}
941
942/*******************************************************************/
943function lesson_print_tree($pageid, $lessonid, $cmid, $pixpath) {
944// this function prints out the tree view list
0733cc00 945 global $USER;
5e7856af 946
947 if(!$pages = get_records_select("lesson_pages", "lessonid = $lessonid")) {
948 error("Error: could not find lesson pages");
949 }
950 echo "<table>";
951 while ($pageid != 0) {
952 echo "<tr><td>";
953 if(($pages[$pageid]->qtype != LESSON_BRANCHTABLE) && ($pages[$pageid]->qtype != LESSON_ENDOFBRANCH)) {
954 $output = "<a style='color:#DF041E;' href=\"view.php?id=$cmid&display=".$pages[$pageid]->id."\">".$pages[$pageid]->title."</a>\n";
955 } else {
956 $output = "<a href=\"view.php?id=$cmid&display=".$pages[$pageid]->id."\">".$pages[$pageid]->title."</a>\n";
957
958 if($answers = get_records_select("lesson_answers", "lessonid = $lessonid and pageid = $pageid")) {
959 $output .= "Jumps to: ";
960 $end = end($answers);
961 foreach ($answers as $answer) {
962 if ($answer->jumpto == 0) {
963 $output .= get_string("thispage", "lesson");
964 } elseif ($answer->jumpto == LESSON_NEXTPAGE) {
965 $output .= get_string("nextpage", "lesson");
966 } elseif ($answer->jumpto == LESSON_EOL) {
967 $output .= get_string("endoflesson", "lesson");
968 } elseif ($answer->jumpto == LESSON_UNSEENBRANCHPAGE) {
969 $output .= get_string("unseenpageinbranch", "lesson");
970 } elseif ($answer->jumpto == LESSON_PREVIOUSPAGE) {
971 $output .= get_string("previouspage", "lesson");
972 } elseif ($answer->jumpto == LESSON_RANDOMPAGE) {
973 $output .= get_string("randompageinbranch", "lesson");
974 } elseif ($answer->jumpto == LESSON_RANDOMBRANCH) {
975 $output .= get_string("randombranch", "lesson");
976 } elseif ($answer->jumpto == LESSON_CLUSTERJUMP) {
977 $output .= get_string("clusterjump", "lesson");
978 } else {
979 $output .= $pages[$answer->jumpto]->title;
980 }
981 if ($answer->id != $end->id) {
982 $output .= ", ";
983 }
984 }
985 }
986 }
987
988 echo $output;
989 if (count($pages) > 1) {
990 echo "<a title=\"move\" href=\"lesson.php?id=$cmid&action=move&pageid=".$pages[$pageid]->id."\">\n".
991 "<img src=\"$pixpath/t/move.gif\" hspace=\"2\" height=11 width=11 alt=\"move\" border=0></a>\n"; //CDC alt text added.
992 }
0733cc00 993 echo "<a title=\"update\" href=\"lesson.php?id=$cmid&amp;action=editpage&amp;pageid=".$pages[$pageid]->id."\">\n".
5e7856af 994 "<img src=\"$pixpath/t/edit.gif\" hspace=\"2\" height=11 width=11 alt=\"edit\" border=0></a>\n".
0733cc00 995 "<a title=\"delete\" href=\"lesson.php?id=$cmid&amp;sesskey=".$USER->sesskey."&amp;action=confirmdelete&amp;pageid=".$pages[$pageid]->id."\">\n".
5e7856af 996 "<img src=\"$pixpath/t/delete.gif\" hspace=\"2\" height=11 width=11 alt=\"delete\" border=0></a>\n"; //CDC alt text added.
997
998 echo "</tr></td>";
999 $pageid = $pages[$pageid]->nextpageid;
1000 }
1001 echo "</table>";
1002}
1003
1004/*******************************************************************/
b9869082 1005function lesson_calculate_ongoing_score($lesson, $userid, $retries, $return=false) {
1006// this calculates and prints the ongoing score for students
5e7856af 1007 if (!$lesson->custom) {
f7ffb898 1008 $ncorrect = 0;
1009 $temp = array();
5e7856af 1010 if ($pagesanswered = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
b9869082 1011 userid = $userid AND retry = $retries order by timeseen")) {
5e7856af 1012
1013 foreach ($pagesanswered as $pageanswered) {
f7ffb898 1014 if (!array_key_exists($pageanswered->pageid, $temp)) {
5e7856af 1015 $temp[$pageanswered->pageid] = array($pageanswered->correct, 1);
1016 } else {
1017 if ($temp[$pageanswered->pageid][1] < $lesson->maxattempts) {
1018 $n = $temp[$pageanswered->pageid][1] + 1;
1019 $temp[$pageanswered->pageid] = array($pageanswered->correct, $n);
1020 }
1021 }
1022 }
1023 foreach ($temp as $value => $key) {
1024 if ($key[0] == 1) {
1025 $ncorrect += 1;
1026 }
1027 }
1028 }
1029 $nviewed = count($temp); // this counts number of Questions the user viewed
324da715 1030 $thegrade = intval(100 * $ncorrect / $nviewed);
1031
1032 if ($return) {
1033 return $thegrade;
1034 } else {
f7ffb898 1035 $output = new stdClass;
324da715 1036 $output->correct = $ncorrect;
1037 $output->viewed = $nviewed;
1038 print_simple_box(get_string("ongoingnormal", "lesson", $output), "center");
1039 }
5e7856af 1040
1041 } else {
1042 $score = 0;
324da715 1043 $essayquestions = 0;
1044 $essayquestionpoints = 0;
1045 $bestscore = 0;
1046 $thegrade = 0;
1047
5e7856af 1048 if ($useranswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
b9869082 1049 userid = $userid AND retry = $retries", "timeseen")) {
324da715 1050 // group each try with its page
5e7856af 1051 foreach ($useranswers as $useranswer) {
324da715 1052 $attemptset[$useranswer->pageid][] = $useranswer;
1053 }
1054
1055 $pageids = array_keys($attemptset);
1056 $pageids = implode(",", $pageids);
1057
1058 // get only the pages and their answers that the user answered
1059 $answeredpages = get_records_select("lesson_pages", "lessonid = $lesson->id AND id IN($pageids)");
1060 $pageanswers = get_records_select("lesson_answers", "lessonid = $lesson->id AND pageid IN($pageids)");
1061
1062 foreach ($attemptset as $attempts) {
1063 if(count($attempts) > $lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt
1064 $attempt = $attempts[$lesson->maxattempts - 1];
5e7856af 1065 } else {
324da715 1066 // else, user attempted the question less than the max, so grab the last one
1067 $attempt = end($attempts);
5e7856af 1068 }
324da715 1069 // if essay question, handle it, otherwise add to score
1070 if ($answeredpages[$attempt->pageid]->qtype == LESSON_ESSAY) {
1071 $essayinfo = unserialize($attempt->useranswer);
1072 $score += $essayinfo->score;
1073 $essayquestions++;
1074 $essayquestionpoints += $pageanswers[$attempt->answerid]->score;
5e7856af 1075 } else {
324da715 1076 $score += $pageanswers[$attempt->answerid]->score;
5e7856af 1077 }
324da715 1078 }
1079 $bestscores = array();
1080 // find the highest possible score per page
1081 foreach ($pageanswers as $pageanswer) {
1082 if(isset($bestscores[$pageanswer->pageid])) {
1083 if ($bestscores[$pageanswer->pageid] < $pageanswer->score) {
1084 $bestscores[$pageanswer->pageid] = $pageanswer->score;
5e7856af 1085 }
324da715 1086 } else {
1087 $bestscores[$pageanswer->pageid] = $pageanswer->score;
5e7856af 1088 }
5e7856af 1089 }
324da715 1090
1091 $bestscore = array_sum($bestscores);
1092 $thegrade = intval(100 * $score / $bestscore);
5e7856af 1093 }
324da715 1094
1095
b9869082 1096 if ($return) {
324da715 1097 return $thegrade;
b9869082 1098 } else {
324da715 1099 // not taking into account essay questions... may want to?
f7ffb898 1100 $ongoingoutput = new stdClass;
b9869082 1101 $ongoingoutput->score = $score;
324da715 1102 $ongoingoutput->currenthigh = $bestscore;
b9869082 1103 print_simple_box(get_string("ongoingcustom", "lesson", $ongoingoutput), "center");
1104 }
5e7856af 1105 }
1106}
1107
1108/*******************************************************************/
1109function lesson_qtype_menu($qtypes, $selected="", $link="", $onclick="") {
1110// prints the question types for when editing and adding a page
1111
1112 $output = "";
1113 foreach ($qtypes as $value => $label) {
1114 if ($value == $selected) {
1115 $output .= "<b>$label</b>";
0733cc00 1116 $output .= "<input type=\"hidden\" name=\"qtype\" value=\"$value\" /> \n";
5e7856af 1117 } else {
1118 $output .= "<a onClick=\"$onclick\" href=\"$link"."&qtype=$value\">$label</a>";
1119 }
1120 if ($label != end($qtypes)) {
1121 $output .= " | ";
1122 }
1123 }
1124 echo $output;
1125}
1126
1127/*******************************************************************/
1128function lesson_check_nickname($name) {
1129// used to check high score nicknames.
1130// checks nickname agains a list of "bad words" in filter.php
1131
1132 if ($name == NULL) {
1133 return false;
1134 }
1135
1136 require_once('filter.php');
1137
1138 foreach ($filterwords as $filterword) {
1139 if (strstr($name, $filterword)) {
1140 return false;
1141 }
1142 }
1143 return true;
1144}
57bfe93d 1145
1146/*******************************************************************/
1147function lesson_clean_data_submitted() {
07fe38c0 1148// this function runs through all post/get data submitted to a page
1149// and runs clean_param on each
1150// returns an object
0733cc00 1151
07fe38c0 1152 // get the data
0733cc00 1153 if ($form = data_submitted()) {
1154 // run through and clean each form value
1155 // detect arrays as well and process them accordingly
1156 foreach ($form as $valuename => $formvalue) {
1157 if (is_array($formvalue)) {
1158 foreach ($formvalue as $index => $formsubvalue) {
1159 $formvalue[$index] = clean_param($formsubvalue, PARAM_CLEAN);
1160 }
1161 $form->$valuename = $formvalue;
1162 } else {
1163 $form->$valuename = clean_param($formvalue, PARAM_CLEAN);
57bfe93d 1164 }
57bfe93d 1165 }
1166 }
1167
1168 return $form;
1169}
1170
5e7856af 1171/// CDC-FLAG ///
1172
2a488ba5 1173?>