|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00029 defined('MOODLE_INTERNAL') || die(); 00030 00032 require_once($CFG->dirroot.'/course/moodleform_mod.php'); 00033 require_once($CFG->dirroot . '/mod/lesson/lib.php'); 00034 require_once($CFG->libdir . '/filelib.php'); 00035 00037 define('LESSON_THISPAGE', 0); 00039 define("LESSON_UNSEENPAGE", 1); 00041 define("LESSON_UNANSWEREDPAGE", 2); 00043 define("LESSON_NEXTPAGE", -1); 00045 define("LESSON_EOL", -9); 00047 define("LESSON_UNSEENBRANCHPAGE", -50); 00049 define("LESSON_PREVIOUSPAGE", -40); 00051 define("LESSON_RANDOMPAGE", -60); 00053 define("LESSON_RANDOMBRANCH", -70); 00055 define("LESSON_CLUSTERJUMP", -80); 00057 define("LESSON_UNDEFINED", -99); 00058 00060 define("LESSON_MAX_EVENT_LENGTH", "432000"); 00061 00062 00066 00077 function lesson_display_teacher_warning($lesson) { 00078 global $DB; 00079 00080 // get all of the lesson answers 00081 $params = array ("lessonid" => $lesson->id); 00082 if (!$lessonanswers = $DB->get_records_select("lesson_answers", "lessonid = :lessonid", $params)) { 00083 // no answers, then not using cluster or unseen 00084 return false; 00085 } 00086 // just check for the first one that fulfills the requirements 00087 foreach ($lessonanswers as $lessonanswer) { 00088 if ($lessonanswer->jumpto == LESSON_CLUSTERJUMP || $lessonanswer->jumpto == LESSON_UNSEENBRANCHPAGE) { 00089 return true; 00090 } 00091 } 00092 00093 // if no answers use either of the two jumps 00094 return false; 00095 } 00096 00107 function lesson_unseen_question_jump($lesson, $user, $pageid) { 00108 global $DB; 00109 00110 // get the number of retakes 00111 if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$user))) { 00112 $retakes = 0; 00113 } 00114 00115 // get all the lesson_attempts aka what the user has seen 00116 if ($viewedpages = $DB->get_records("lesson_attempts", array("lessonid"=>$lesson->id, "userid"=>$user, "retry"=>$retakes), "timeseen DESC")) { 00117 foreach($viewedpages as $viewed) { 00118 $seenpages[] = $viewed->pageid; 00119 } 00120 } else { 00121 $seenpages = array(); 00122 } 00123 00124 // get the lesson pages 00125 $lessonpages = $lesson->load_all_pages(); 00126 00127 if ($pageid == LESSON_UNSEENBRANCHPAGE) { // this only happens when a student leaves in the middle of an unseen question within a branch series 00128 $pageid = $seenpages[0]; // just change the pageid to the last page viewed inside the branch table 00129 } 00130 00131 // go up the pages till branch table 00132 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page 00133 if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) { 00134 break; 00135 } 00136 $pageid = $lessonpages[$pageid]->prevpageid; 00137 } 00138 00139 $pagesinbranch = $lesson->get_sub_pages_of($pageid, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH)); 00140 00141 // this foreach loop stores all the pages that are within the branch table but are not in the $seenpages array 00142 $unseen = array(); 00143 foreach($pagesinbranch as $page) { 00144 if (!in_array($page->id, $seenpages)) { 00145 $unseen[] = $page->id; 00146 } 00147 } 00148 00149 if(count($unseen) == 0) { 00150 if(isset($pagesinbranch)) { 00151 $temp = end($pagesinbranch); 00152 $nextpage = $temp->nextpageid; // they have seen all the pages in the branch, so go to EOB/next branch table/EOL 00153 } else { 00154 // there are no pages inside the branch, so return the next page 00155 $nextpage = $lessonpages[$pageid]->nextpageid; 00156 } 00157 if ($nextpage == 0) { 00158 return LESSON_EOL; 00159 } else { 00160 return $nextpage; 00161 } 00162 } else { 00163 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page 00164 } 00165 } 00166 00174 function lesson_unseen_branch_jump($lesson, $userid) { 00175 global $DB; 00176 00177 if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$userid))) { 00178 $retakes = 0; 00179 } 00180 00181 $params = array ("lessonid" => $lesson->id, "userid" => $userid, "retry" => $retakes); 00182 if (!$seenbranches = $DB->get_records_select("lesson_branch", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params, 00183 "timeseen DESC")) { 00184 print_error('cannotfindrecords', 'lesson'); 00185 } 00186 00187 // get the lesson pages 00188 $lessonpages = $lesson->load_all_pages(); 00189 00190 // this loads all the viewed branch tables into $seen until it finds the branch table with the flag 00191 // which is the branch table that starts the unseenbranch function 00192 $seen = array(); 00193 foreach ($seenbranches as $seenbranch) { 00194 if (!$seenbranch->flag) { 00195 $seen[$seenbranch->pageid] = $seenbranch->pageid; 00196 } else { 00197 $start = $seenbranch->pageid; 00198 break; 00199 } 00200 } 00201 // this function searches through the lesson pages to find all the branch tables 00202 // that follow the flagged branch table 00203 $pageid = $lessonpages[$start]->nextpageid; // move down from the flagged branch table 00204 while ($pageid != 0) { // grab all of the branch table till eol 00205 if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) { 00206 $branchtables[] = $lessonpages[$pageid]->id; 00207 } 00208 $pageid = $lessonpages[$pageid]->nextpageid; 00209 } 00210 $unseen = array(); 00211 foreach ($branchtables as $branchtable) { 00212 // load all of the unseen branch tables into unseen 00213 if (!array_key_exists($branchtable, $seen)) { 00214 $unseen[] = $branchtable; 00215 } 00216 } 00217 if (count($unseen) > 0) { 00218 return $unseen[rand(0, count($unseen)-1)]; // returns a random page id for the next page 00219 } else { 00220 return LESSON_EOL; // has viewed all of the branch tables 00221 } 00222 } 00223 00231 function lesson_random_question_jump($lesson, $pageid) { 00232 global $DB; 00233 00234 // get the lesson pages 00235 $params = array ("lessonid" => $lesson->id); 00236 if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) { 00237 print_error('cannotfindpages', 'lesson'); 00238 } 00239 00240 // go up the pages till branch table 00241 while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page 00242 00243 if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) { 00244 break; 00245 } 00246 $pageid = $lessonpages[$pageid]->prevpageid; 00247 } 00248 00249 // get the pages within the branch 00250 $pagesinbranch = $lesson->get_sub_pages_of($pageid, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH)); 00251 00252 if(count($pagesinbranch) == 0) { 00253 // there are no pages inside the branch, so return the next page 00254 return $lessonpages[$pageid]->nextpageid; 00255 } else { 00256 return $pagesinbranch[rand(0, count($pagesinbranch)-1)]->id; // returns a random page id for the next page 00257 } 00258 } 00259 00274 function lesson_grade($lesson, $ntries, $userid = 0) { 00275 global $USER, $DB; 00276 00277 if (empty($userid)) { 00278 $userid = $USER->id; 00279 } 00280 00281 // Zero out everything 00282 $ncorrect = 0; 00283 $nviewed = 0; 00284 $score = 0; 00285 $nmanual = 0; 00286 $manualpoints = 0; 00287 $thegrade = 0; 00288 $nquestions = 0; 00289 $total = 0; 00290 $earned = 0; 00291 00292 $params = array ("lessonid" => $lesson->id, "userid" => $userid, "retry" => $ntries); 00293 if ($useranswers = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND 00294 userid = :userid AND retry = :retry", $params, "timeseen")) { 00295 // group each try with its page 00296 $attemptset = array(); 00297 foreach ($useranswers as $useranswer) { 00298 $attemptset[$useranswer->pageid][] = $useranswer; 00299 } 00300 00301 // Drop all attempts that go beyond max attempts for the lesson 00302 foreach ($attemptset as $key => $set) { 00303 $attemptset[$key] = array_slice($set, 0, $lesson->maxattempts); 00304 } 00305 00306 // get only the pages and their answers that the user answered 00307 list($usql, $parameters) = $DB->get_in_or_equal(array_keys($attemptset)); 00308 array_unshift($parameters, $lesson->id); 00309 $pages = $DB->get_records_select("lesson_pages", "lessonid = ? AND id $usql", $parameters); 00310 $answers = $DB->get_records_select("lesson_answers", "lessonid = ? AND pageid $usql", $parameters); 00311 00312 // Number of pages answered 00313 $nquestions = count($pages); 00314 00315 foreach ($attemptset as $attempts) { 00316 $page = lesson_page::load($pages[end($attempts)->pageid], $lesson); 00317 if ($lesson->custom) { 00318 $attempt = end($attempts); 00319 // If essay question, handle it, otherwise add to score 00320 if ($page->requires_manual_grading()) { 00321 $useranswerobj = unserialize($attempt->useranswer); 00322 if (isset($useranswerobj->score)) { 00323 $earned += $useranswerobj->score; 00324 } 00325 $nmanual++; 00326 $manualpoints += $answers[$attempt->answerid]->score; 00327 } else if (!empty($attempt->answerid)) { 00328 $earned += $page->earned_score($answers, $attempt); 00329 } 00330 } else { 00331 foreach ($attempts as $attempt) { 00332 $earned += $attempt->correct; 00333 } 00334 $attempt = end($attempts); // doesn't matter which one 00335 // If essay question, increase numbers 00336 if ($page->requires_manual_grading()) { 00337 $nmanual++; 00338 $manualpoints++; 00339 } 00340 } 00341 // Number of times answered 00342 $nviewed += count($attempts); 00343 } 00344 00345 if ($lesson->custom) { 00346 $bestscores = array(); 00347 // Find the highest possible score per page to get our total 00348 foreach ($answers as $answer) { 00349 if(!isset($bestscores[$answer->pageid])) { 00350 $bestscores[$answer->pageid] = $answer->score; 00351 } else if ($bestscores[$answer->pageid] < $answer->score) { 00352 $bestscores[$answer->pageid] = $answer->score; 00353 } 00354 } 00355 $total = array_sum($bestscores); 00356 } else { 00357 // Check to make sure the student has answered the minimum questions 00358 if ($lesson->minquestions and $nquestions < $lesson->minquestions) { 00359 // Nope, increase number viewed by the amount of unanswered questions 00360 $total = $nviewed + ($lesson->minquestions - $nquestions); 00361 } else { 00362 $total = $nviewed; 00363 } 00364 } 00365 } 00366 00367 if ($total) { // not zero 00368 $thegrade = round(100 * $earned / $total, 5); 00369 } 00370 00371 // Build the grade information object 00372 $gradeinfo = new stdClass; 00373 $gradeinfo->nquestions = $nquestions; 00374 $gradeinfo->attempts = $nviewed; 00375 $gradeinfo->total = $total; 00376 $gradeinfo->earned = $earned; 00377 $gradeinfo->grade = $thegrade; 00378 $gradeinfo->nmanual = $nmanual; 00379 $gradeinfo->manualpoints = $manualpoints; 00380 00381 return $gradeinfo; 00382 } 00383 00392 function lesson_displayleftif($lesson) { 00393 global $CFG, $USER, $DB; 00394 00395 if (!empty($lesson->displayleftif)) { 00396 // get the current user's max grade for this lesson 00397 $params = array ("userid" => $USER->id, "lessonid" => $lesson->id); 00398 if ($maxgrade = $DB->get_record_sql('SELECT userid, MAX(grade) AS maxgrade FROM {lesson_grades} WHERE userid = :userid AND lessonid = :lessonid GROUP BY userid', $params)) { 00399 if ($maxgrade->maxgrade < $lesson->displayleftif) { 00400 return 0; // turn off the displayleft 00401 } 00402 } else { 00403 return 0; // no grades 00404 } 00405 } 00406 00407 // if we get to here, keep the original state of displayleft lesson setting 00408 return $lesson->displayleft; 00409 } 00410 00418 function lesson_add_fake_blocks($page, $cm, $lesson, $timer = null) { 00419 $bc = lesson_menu_block_contents($cm->id, $lesson); 00420 if (!empty($bc)) { 00421 $regions = $page->blocks->get_regions(); 00422 $firstregion = reset($regions); 00423 $page->blocks->add_fake_block($bc, $firstregion); 00424 } 00425 00426 $bc = lesson_mediafile_block_contents($cm->id, $lesson); 00427 if (!empty($bc)) { 00428 $page->blocks->add_fake_block($bc, $page->blocks->get_default_region()); 00429 } 00430 00431 if (!empty($timer)) { 00432 $bc = lesson_clock_block_contents($cm->id, $lesson, $timer, $page); 00433 if (!empty($bc)) { 00434 $page->blocks->add_fake_block($bc, $page->blocks->get_default_region()); 00435 } 00436 } 00437 } 00438 00447 function lesson_mediafile_block_contents($cmid, $lesson) { 00448 global $OUTPUT; 00449 if (empty($lesson->mediafile)) { 00450 return null; 00451 } 00452 00453 $options = array(); 00454 $options['menubar'] = 0; 00455 $options['location'] = 0; 00456 $options['left'] = 5; 00457 $options['top'] = 5; 00458 $options['scrollbars'] = 1; 00459 $options['resizable'] = 1; 00460 $options['width'] = $lesson->mediawidth; 00461 $options['height'] = $lesson->mediaheight; 00462 00463 $link = new moodle_url('/mod/lesson/mediafile.php?id='.$cmid); 00464 $action = new popup_action('click', $link, 'lessonmediafile', $options); 00465 $content = $OUTPUT->action_link($link, get_string('mediafilepopup', 'lesson'), $action, array('title'=>get_string('mediafilepopup', 'lesson'))); 00466 00467 $bc = new block_contents(); 00468 $bc->title = get_string('linkedmedia', 'lesson'); 00469 $bc->attributes['class'] = 'mediafile'; 00470 $bc->content = $content; 00471 00472 return $bc; 00473 } 00474 00484 function lesson_clock_block_contents($cmid, $lesson, $timer, $page) { 00485 // Display for timed lessons and for students only 00486 $context = get_context_instance(CONTEXT_MODULE, $cmid); 00487 if(!$lesson->timed || has_capability('mod/lesson:manage', $context)) { 00488 return null; 00489 } 00490 00491 $content = '<div class="jshidewhenenabled">'; 00492 $content .= $lesson->time_remaining($timer->starttime); 00493 $content .= '</div>'; 00494 00495 $clocksettings = array('starttime'=>$timer->starttime, 'servertime'=>time(),'testlength'=>($lesson->maxtime * 60)); 00496 $page->requires->data_for_js('clocksettings', $clocksettings); 00497 $page->requires->js('/mod/lesson/timer.js'); 00498 $page->requires->js_function_call('show_clock'); 00499 00500 $bc = new block_contents(); 00501 $bc->title = get_string('timeremaining', 'lesson'); 00502 $bc->attributes['class'] = 'clock block'; 00503 $bc->content = $content; 00504 00505 return $bc; 00506 } 00507 00516 function lesson_menu_block_contents($cmid, $lesson) { 00517 global $CFG, $DB; 00518 00519 if (!$lesson->displayleft) { 00520 return null; 00521 } 00522 00523 $pages = $lesson->load_all_pages(); 00524 foreach ($pages as $page) { 00525 if ((int)$page->prevpageid === 0) { 00526 $pageid = $page->id; 00527 break; 00528 } 00529 } 00530 $currentpageid = optional_param('pageid', $pageid, PARAM_INT); 00531 00532 if (!$pageid || !$pages) { 00533 return null; 00534 } 00535 00536 $content = '<a href="#maincontent" class="skip">'.get_string('skip', 'lesson')."</a>\n<div class=\"menuwrapper\">\n<ul>\n"; 00537 00538 while ($pageid != 0) { 00539 $page = $pages[$pageid]; 00540 00541 // Only process branch tables with display turned on 00542 if ($page->displayinmenublock && $page->display) { 00543 if ($page->id == $currentpageid) { 00544 $content .= '<li class="selected">'.format_string($page->title,true)."</li>\n"; 00545 } else { 00546 $content .= "<li class=\"notselected\"><a href=\"$CFG->wwwroot/mod/lesson/view.php?id=$cmid&pageid=$page->id\">".format_string($page->title,true)."</a></li>\n"; 00547 } 00548 00549 } 00550 $pageid = $page->nextpageid; 00551 } 00552 $content .= "</ul>\n</div>\n"; 00553 00554 $bc = new block_contents(); 00555 $bc->title = get_string('lessonmenu', 'lesson'); 00556 $bc->attributes['class'] = 'menu block'; 00557 $bc->content = $content; 00558 00559 return $bc; 00560 } 00561 00570 function lesson_add_header_buttons($cm, $context, $extraeditbuttons=false, $lessonpageid=null) { 00571 global $CFG, $PAGE, $OUTPUT; 00572 if (has_capability('mod/lesson:edit', $context) && $extraeditbuttons) { 00573 if ($lessonpageid === null) { 00574 print_error('invalidpageid', 'lesson'); 00575 } 00576 if (!empty($lessonpageid) && $lessonpageid != LESSON_EOL) { 00577 $url = new moodle_url('/mod/lesson/editpage.php', array('id'=>$cm->id, 'pageid'=>$lessonpageid, 'edit'=>1)); 00578 $PAGE->set_button($OUTPUT->single_button($url, get_string('editpagecontent', 'lesson'))); 00579 } 00580 } 00581 } 00582 00592 function lesson_get_media_html($lesson, $context) { 00593 global $CFG, $PAGE, $OUTPUT; 00594 require_once("$CFG->libdir/resourcelib.php"); 00595 00596 // get the media file link 00597 if (strpos($lesson->mediafile, '://') !== false) { 00598 $url = new moodle_url($lesson->mediafile); 00599 } else { 00600 // the timemodified is used to prevent caching problems, instead of '/' we should better read from files table and use sortorder 00601 $url = moodle_url::make_pluginfile_url($context->id, 'mod_lesson', 'mediafile', $lesson->timemodified, '/', ltrim($lesson->mediafile, '/')); 00602 } 00603 $title = $lesson->mediafile; 00604 00605 $clicktoopen = html_writer::link($url, get_string('download')); 00606 00607 $mimetype = resourcelib_guess_url_mimetype($url); 00608 00609 $extension = resourcelib_get_extension($url->out(false)); 00610 00611 // find the correct type and print it out 00612 if (in_array($mimetype, array('image/gif','image/jpeg','image/png'))) { // It's an image 00613 $code = resourcelib_embed_image($url, $title); 00614 00615 } else if ($mimetype == 'audio/mp3') { 00616 // MP3 audio file 00617 $code = resourcelib_embed_mp3($url, $title, $clicktoopen); 00618 00619 } else if ($mimetype == 'video/x-flv' or $extension === 'f4v') { 00620 // Flash video file 00621 $code = resourcelib_embed_flashvideo($url, $title, $clicktoopen); 00622 00623 } else if ($mimetype == 'application/x-shockwave-flash') { 00624 // Flash file 00625 $code = resourcelib_embed_flash($url, $title, $clicktoopen); 00626 00627 } else if (substr($mimetype, 0, 10) == 'video/x-ms') { 00628 // Windows Media Player file 00629 $code = resourcelib_embed_mediaplayer($url, $title, $clicktoopen); 00630 00631 } else if ($mimetype == 'video/quicktime') { 00632 // Quicktime file 00633 $code = resourcelib_embed_quicktime($url, $title, $clicktoopen); 00634 00635 } else if ($mimetype == 'video/mpeg') { 00636 // Mpeg file 00637 $code = resourcelib_embed_mpeg($url, $title, $clicktoopen); 00638 00639 } else if ($mimetype == 'audio/x-pn-realaudio-plugin') { 00640 // RealMedia file 00641 $code = resourcelib_embed_real($url, $title, $clicktoopen); 00642 00643 } else { 00644 // anything else - just try object tag enlarged as much as possible 00645 $code = resourcelib_embed_general($url, $title, $clicktoopen, $mimetype); 00646 } 00647 00648 return $code; 00649 } 00650 00651 00664 abstract class lesson_add_page_form_base extends moodleform { 00665 00671 public $qtype; 00672 00677 public $qtypestring; 00678 00683 protected $editoroptions = array(); 00684 00690 protected $standard = true; 00691 00696 public function custom_definition() {} 00697 00702 public final function is_standard() { 00703 return (bool)$this->standard; 00704 } 00705 00712 public final function definition() { 00713 $mform = $this->_form; 00714 $editoroptions = $this->_customdata['editoroptions']; 00715 00716 $mform->addElement('header', 'qtypeheading', get_string('addaquestionpage', 'lesson', get_string($this->qtypestring, 'lesson'))); 00717 00718 $mform->addElement('hidden', 'id'); 00719 $mform->setType('id', PARAM_INT); 00720 00721 $mform->addElement('hidden', 'pageid'); 00722 $mform->setType('pageid', PARAM_INT); 00723 00724 if ($this->standard === true) { 00725 $mform->addElement('hidden', 'qtype'); 00726 $mform->setType('qtype', PARAM_INT); 00727 00728 $mform->addElement('text', 'title', get_string('pagetitle', 'lesson'), array('size'=>70)); 00729 $mform->setType('title', PARAM_TEXT); 00730 $mform->addRule('title', get_string('required'), 'required', null, 'client'); 00731 00732 $this->editoroptions = array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$this->_customdata['maxbytes']); 00733 $mform->addElement('editor', 'contents_editor', get_string('pagecontents', 'lesson'), null, $this->editoroptions); 00734 $mform->setType('contents_editor', PARAM_RAW); 00735 $mform->addRule('contents_editor', get_string('required'), 'required', null, 'client'); 00736 } 00737 00738 $this->custom_definition(); 00739 00740 if ($this->_customdata['edit'] === true) { 00741 $mform->addElement('hidden', 'edit', 1); 00742 $this->add_action_buttons(get_string('cancel'), get_string('savepage', 'lesson')); 00743 } else { 00744 $this->add_action_buttons(get_string('cancel'), get_string('addaquestionpage', 'lesson')); 00745 } 00746 } 00747 00755 protected final function add_jumpto($name, $label=null, $selected=LESSON_NEXTPAGE) { 00756 $title = get_string("jump", "lesson"); 00757 if ($label === null) { 00758 $label = $title; 00759 } 00760 if (is_int($name)) { 00761 $name = "jumpto[$name]"; 00762 } 00763 $this->_form->addElement('select', $name, $label, $this->_customdata['jumpto']); 00764 $this->_form->setDefault($name, $selected); 00765 $this->_form->addHelpButton($name, 'jumps', 'lesson'); 00766 } 00767 00775 protected final function add_score($name, $label=null, $value=null) { 00776 if ($label === null) { 00777 $label = get_string("score", "lesson"); 00778 } 00779 if (is_int($name)) { 00780 $name = "score[$name]"; 00781 } 00782 $this->_form->addElement('text', $name, $label, array('size'=>5)); 00783 if ($value !== null) { 00784 $this->_form->setDefault($name, $value); 00785 } 00786 } 00787 00796 protected final function add_answer($count, $label = NULL, $required = false) { 00797 if ($label === NULL) { 00798 $label = get_string('answer', 'lesson'); 00799 } 00800 $this->_form->addElement('editor', 'answer_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true)); 00801 $this->_form->setDefault('answer_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE)); 00802 if ($required) { 00803 $this->_form->addRule('answer_editor['.$count.']', get_string('required'), 'required', null, 'client'); 00804 } 00805 } 00814 protected final function add_response($count, $label = NULL, $required = false) { 00815 if ($label === NULL) { 00816 $label = get_string('response', 'lesson'); 00817 } 00818 $this->_form->addElement('editor', 'response_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true)); 00819 $this->_form->setDefault('response_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE)); 00820 if ($required) { 00821 $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client'); 00822 } 00823 } 00824 00833 public function construction_override() { 00834 return true; 00835 } 00836 } 00837 00838 00839 00902 class lesson extends lesson_base { 00903 00909 protected $firstpageid = null; 00915 protected $lastpageid = null; 00924 protected $pages = array(); 00930 protected $loadedallpages = false; 00931 00939 public static function create($properties) { 00940 return new lesson($properties); 00941 } 00942 00949 public static function load($lessonid) { 00950 global $DB; 00951 00952 if (!$lesson = $DB->get_record('lesson', array('id' => $lessonid))) { 00953 print_error('invalidcoursemodule'); 00954 } 00955 return new lesson($lesson); 00956 } 00957 00961 public function delete() { 00962 global $CFG, $DB; 00963 require_once($CFG->libdir.'/gradelib.php'); 00964 require_once($CFG->dirroot.'/calendar/lib.php'); 00965 00966 $DB->delete_records("lesson", array("id"=>$this->properties->id));; 00967 $DB->delete_records("lesson_pages", array("lessonid"=>$this->properties->id)); 00968 $DB->delete_records("lesson_answers", array("lessonid"=>$this->properties->id)); 00969 $DB->delete_records("lesson_attempts", array("lessonid"=>$this->properties->id)); 00970 $DB->delete_records("lesson_grades", array("lessonid"=>$this->properties->id)); 00971 $DB->delete_records("lesson_timer", array("lessonid"=>$this->properties->id)); 00972 $DB->delete_records("lesson_branch", array("lessonid"=>$this->properties->id)); 00973 $DB->delete_records("lesson_high_scores", array("lessonid"=>$this->properties->id)); 00974 if ($events = $DB->get_records('event', array("modulename"=>'lesson', "instance"=>$this->properties->id))) { 00975 foreach($events as $event) { 00976 $event = calendar_event::load($event); 00977 $event->delete(); 00978 } 00979 } 00980 00981 grade_update('mod/lesson', $this->properties->course, 'mod', 'lesson', $this->properties->id, 0, NULL, array('deleted'=>1)); 00982 return true; 00983 } 00984 00996 protected function get_messages() { 00997 global $SESSION; 00998 00999 $messages = array(); 01000 if (!empty($SESSION->lesson_messages) && is_array($SESSION->lesson_messages) && array_key_exists($this->properties->id, $SESSION->lesson_messages)) { 01001 $messages = $SESSION->lesson_messages[$this->properties->id]; 01002 unset($SESSION->lesson_messages[$this->properties->id]); 01003 } 01004 01005 return $messages; 01006 } 01007 01017 public function get_attempts($retries, $correct=false, $pageid=null, $userid=null) { 01018 global $USER, $DB; 01019 $params = array("lessonid"=>$this->properties->id, "userid"=>$userid, "retry"=>$retries); 01020 if ($correct) { 01021 $params['correct'] = 1; 01022 } 01023 if ($pageid !== null) { 01024 $params['pageid'] = $pageid; 01025 } 01026 if ($userid === null) { 01027 $params['userid'] = $USER->id; 01028 } 01029 return $DB->get_records('lesson_attempts', $params, 'timeseen ASC'); 01030 } 01031 01042 protected function get_firstpage() { 01043 $pages = $this->load_all_pages(); 01044 if (count($pages) > 0) { 01045 foreach ($pages as $page) { 01046 if ((int)$page->prevpageid === 0) { 01047 return $page; 01048 } 01049 } 01050 } 01051 return false; 01052 } 01053 01064 protected function get_lastpage() { 01065 $pages = $this->load_all_pages(); 01066 if (count($pages) > 0) { 01067 foreach ($pages as $page) { 01068 if ((int)$page->nextpageid === 0) { 01069 return $page; 01070 } 01071 } 01072 } 01073 return false; 01074 } 01075 01080 protected function get_firstpageid() { 01081 global $DB; 01082 if ($this->firstpageid == null) { 01083 if (!$this->loadedallpages) { 01084 $firstpageid = $DB->get_field('lesson_pages', 'id', array('lessonid'=>$this->properties->id, 'prevpageid'=>0)); 01085 if (!$firstpageid) { 01086 print_error('cannotfindfirstpage', 'lesson'); 01087 } 01088 $this->firstpageid = $firstpageid; 01089 } else { 01090 $firstpage = $this->get_firstpage(); 01091 $this->firstpageid = $firstpage->id; 01092 } 01093 } 01094 return $this->firstpageid; 01095 } 01096 01101 public function get_lastpageid() { 01102 global $DB; 01103 if ($this->lastpageid == null) { 01104 if (!$this->loadedallpages) { 01105 $lastpageid = $DB->get_field('lesson_pages', 'id', array('lessonid'=>$this->properties->id, 'nextpageid'=>0)); 01106 if (!$lastpageid) { 01107 print_error('cannotfindlastpage', 'lesson'); 01108 } 01109 $this->lastpageid = $lastpageid; 01110 } else { 01111 $lastpageid = $this->get_lastpage(); 01112 $this->lastpageid = $lastpageid->id; 01113 } 01114 } 01115 01116 return $this->lastpageid; 01117 } 01118 01124 public function get_next_page($nextpageid) { 01125 global $USER, $DB; 01126 $allpages = $this->load_all_pages(); 01127 if ($this->properties->nextpagedefault) { 01128 // in Flash Card mode...first get number of retakes 01129 $nretakes = $DB->count_records("lesson_grades", array("lessonid" => $this->properties->id, "userid" => $USER->id)); 01130 shuffle($allpages); 01131 $found = false; 01132 if ($this->properties->nextpagedefault == LESSON_UNSEENPAGE) { 01133 foreach ($allpages as $nextpage) { 01134 if (!$DB->count_records("lesson_attempts", array("pageid" => $nextpage->id, "userid" => $USER->id, "retry" => $nretakes))) { 01135 $found = true; 01136 break; 01137 } 01138 } 01139 } elseif ($this->properties->nextpagedefault == LESSON_UNANSWEREDPAGE) { 01140 foreach ($allpages as $nextpage) { 01141 if (!$DB->count_records("lesson_attempts", array('pageid' => $nextpage->id, 'userid' => $USER->id, 'correct' => 1, 'retry' => $nretakes))) { 01142 $found = true; 01143 break; 01144 } 01145 } 01146 } 01147 if ($found) { 01148 if ($this->properties->maxpages) { 01149 // check number of pages viewed (in the lesson) 01150 if ($DB->count_records("lesson_attempts", array("lessonid" => $this->properties->id, "userid" => $USER->id, "retry" => $nretakes)) >= $this->properties->maxpages) { 01151 return LESSON_EOL; 01152 } 01153 } 01154 return $nextpage->id; 01155 } 01156 } 01157 // In a normal lesson mode 01158 foreach ($allpages as $nextpage) { 01159 if ((int)$nextpage->id === (int)$nextpageid) { 01160 return $nextpage->id; 01161 } 01162 } 01163 return LESSON_EOL; 01164 } 01165 01175 public function add_message($message, $class="notifyproblem", $align='center') { 01176 global $SESSION; 01177 01178 if (empty($SESSION->lesson_messages) || !is_array($SESSION->lesson_messages)) { 01179 $SESSION->lesson_messages = array(); 01180 $SESSION->lesson_messages[$this->properties->id] = array(); 01181 } else if (!array_key_exists($this->properties->id, $SESSION->lesson_messages)) { 01182 $SESSION->lesson_messages[$this->properties->id] = array(); 01183 } 01184 01185 $SESSION->lesson_messages[$this->properties->id][] = array($message, $class, $align); 01186 01187 return true; 01188 } 01189 01194 public function is_accessible() { 01195 $available = $this->properties->available; 01196 $deadline = $this->properties->deadline; 01197 return (($available == 0 || time() >= $available) && ($deadline == 0 || time() < $deadline)); 01198 } 01199 01204 public function start_timer() { 01205 global $USER, $DB; 01206 $USER->startlesson[$this->properties->id] = true; 01207 $startlesson = new stdClass; 01208 $startlesson->lessonid = $this->properties->id; 01209 $startlesson->userid = $USER->id; 01210 $startlesson->starttime = time(); 01211 $startlesson->lessontime = time(); 01212 $DB->insert_record('lesson_timer', $startlesson); 01213 if ($this->properties->timed) { 01214 $this->add_message(get_string('maxtimewarning', 'lesson', $this->properties->maxtime), 'center'); 01215 } 01216 return true; 01217 } 01218 01226 public function update_timer($restart=false, $continue=false) { 01227 global $USER, $DB; 01228 // clock code 01229 // get time information for this user 01230 if (!$timer = $DB->get_records('lesson_timer', array ("lessonid" => $this->properties->id, "userid" => $USER->id), 'starttime DESC', '*', 0, 1)) { 01231 print_error('cannotfindtimer', 'lesson'); 01232 } else { 01233 $timer = current($timer); // this will get the latest start time record 01234 } 01235 01236 if ($restart) { 01237 if ($continue) { 01238 // continue a previous test, need to update the clock (think this option is disabled atm) 01239 $timer->starttime = time() - ($timer->lessontime - $timer->starttime); 01240 } else { 01241 // starting over, so reset the clock 01242 $timer->starttime = time(); 01243 } 01244 } 01245 01246 $timer->lessontime = time(); 01247 $DB->update_record('lesson_timer', $timer); 01248 return $timer; 01249 } 01250 01255 public function stop_timer() { 01256 global $USER, $DB; 01257 unset($USER->startlesson[$this->properties->id]); 01258 return $this->update_timer(false, false); 01259 } 01260 01264 public function has_pages() { 01265 global $DB; 01266 $pagecount = $DB->count_records('lesson_pages', array('lessonid'=>$this->properties->id)); 01267 return ($pagecount>0); 01268 } 01269 01274 public function link_for_activitylink() { 01275 global $DB; 01276 $module = $DB->get_record('course_modules', array('id' => $this->properties->activitylink)); 01277 if ($module) { 01278 $modname = $DB->get_field('modules', 'name', array('id' => $module->module)); 01279 if ($modname) { 01280 $instancename = $DB->get_field($modname, 'name', array('id' => $module->instance)); 01281 if ($instancename) { 01282 return html_writer::link(new moodle_url('/mod/'.$modname.'/view.php', array('id'=>$this->properties->activitylink)), 01283 get_string('activitylinkname', 'lesson', $instancename), 01284 array('class'=>'centerpadded lessonbutton standardbutton')); 01285 } 01286 } 01287 } 01288 return ''; 01289 } 01290 01302 public function load_page($pageid) { 01303 if (!array_key_exists($pageid, $this->pages)) { 01304 $manager = lesson_page_type_manager::get($this); 01305 $this->pages[$pageid] = $manager->load_page($pageid, $this); 01306 } 01307 return $this->pages[$pageid]; 01308 } 01309 01315 public function load_all_pages() { 01316 if (!$this->loadedallpages) { 01317 $manager = lesson_page_type_manager::get($this); 01318 $this->pages = $manager->load_all_pages($this); 01319 $this->loadedallpages = true; 01320 } 01321 return $this->pages; 01322 } 01323 01334 public function jumpto_is_correct($pageid, $jumpto) { 01335 global $DB; 01336 01337 // first test the special values 01338 if (!$jumpto) { 01339 // same page 01340 return false; 01341 } elseif ($jumpto == LESSON_NEXTPAGE) { 01342 return true; 01343 } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) { 01344 return true; 01345 } elseif ($jumpto == LESSON_RANDOMPAGE) { 01346 return true; 01347 } elseif ($jumpto == LESSON_CLUSTERJUMP) { 01348 return true; 01349 } elseif ($jumpto == LESSON_EOL) { 01350 return true; 01351 } 01352 01353 $pages = $this->load_all_pages(); 01354 $apageid = $pages[$pageid]->nextpageid; 01355 while ($apageid != 0) { 01356 if ($jumpto == $apageid) { 01357 return true; 01358 } 01359 $apageid = $pages[$apageid]->nextpageid; 01360 } 01361 return false; 01362 } 01363 01369 public function time_remaining($starttime) { 01370 $timeleft = $starttime + $this->maxtime * 60 - time(); 01371 $hours = floor($timeleft/3600); 01372 $timeleft = $timeleft - ($hours * 3600); 01373 $minutes = floor($timeleft/60); 01374 $secs = $timeleft - ($minutes * 60); 01375 01376 if ($minutes < 10) { 01377 $minutes = "0$minutes"; 01378 } 01379 if ($secs < 10) { 01380 $secs = "0$secs"; 01381 } 01382 $output = array(); 01383 $output[] = $hours; 01384 $output[] = $minutes; 01385 $output[] = $secs; 01386 $output = implode(':', $output); 01387 return $output; 01388 } 01389 01403 public function cluster_jump($pageid, $userid=null) { 01404 global $DB, $USER; 01405 01406 if ($userid===null) { 01407 $userid = $USER->id; 01408 } 01409 // get the number of retakes 01410 if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->properties->id, "userid"=>$userid))) { 01411 $retakes = 0; 01412 } 01413 // get all the lesson_attempts aka what the user has seen 01414 $seenpages = array(); 01415 if ($attempts = $this->get_attempts($retakes)) { 01416 foreach ($attempts as $attempt) { 01417 $seenpages[$attempt->pageid] = $attempt->pageid; 01418 } 01419 01420 } 01421 01422 // get the lesson pages 01423 $lessonpages = $this->load_all_pages(); 01424 // find the start of the cluster 01425 while ($pageid != 0) { // this condition should not be satisfied... should be a cluster page 01426 if ($lessonpages[$pageid]->qtype == LESSON_PAGE_CLUSTER) { 01427 break; 01428 } 01429 $pageid = $lessonpages[$pageid]->prevpageid; 01430 } 01431 01432 $clusterpages = array(); 01433 $clusterpages = $this->get_sub_pages_of($pageid, array(LESSON_PAGE_ENDOFCLUSTER)); 01434 $unseen = array(); 01435 foreach ($clusterpages as $key=>$cluster) { 01436 if ($cluster->type !== lesson_page::TYPE_QUESTION) { 01437 unset($clusterpages[$key]); 01438 } elseif ($cluster->is_unseen($seenpages)) { 01439 $unseen[] = $cluster; 01440 } 01441 } 01442 01443 if (count($unseen) > 0) { 01444 // it does not contain elements, then use exitjump, otherwise find out next page/branch 01445 $nextpage = $unseen[rand(0, count($unseen)-1)]; 01446 if ($nextpage->qtype == LESSON_PAGE_BRANCHTABLE) { 01447 // if branch table, then pick a random page inside of it 01448 $branchpages = $this->get_sub_pages_of($nextpage->id, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH)); 01449 return $branchpages[rand(0, count($branchpages)-1)]->id; 01450 } else { // otherwise, return the page's id 01451 return $nextpage->id; 01452 } 01453 } else { 01454 // seen all there is to see, leave the cluster 01455 if (end($clusterpages)->nextpageid == 0) { 01456 return LESSON_EOL; 01457 } else { 01458 $clusterendid = $pageid; 01459 while ($clusterendid != 0) { // this condition should not be satisfied... should be a cluster page 01460 if ($lessonpages[$clusterendid]->qtype == LESSON_PAGE_CLUSTER) { 01461 break; 01462 } 01463 $clusterendid = $lessonpages[$clusterendid]->prevpageid; 01464 } 01465 $exitjump = $DB->get_field("lesson_answers", "jumpto", array("pageid" => $clusterendid, "lessonid" => $this->properties->id)); 01466 if ($exitjump == LESSON_NEXTPAGE) { 01467 $exitjump = $lessonpages[$pageid]->nextpageid; 01468 } 01469 if ($exitjump == 0) { 01470 return LESSON_EOL; 01471 } else if (in_array($exitjump, array(LESSON_EOL, LESSON_PREVIOUSPAGE))) { 01472 return $exitjump; 01473 } else { 01474 if (!array_key_exists($exitjump, $lessonpages)) { 01475 $found = false; 01476 foreach ($lessonpages as $page) { 01477 if ($page->id === $clusterendid) { 01478 $found = true; 01479 } else if ($page->qtype == LESSON_PAGE_ENDOFCLUSTER) { 01480 $exitjump = $DB->get_field("lesson_answers", "jumpto", array("pageid" => $page->id, "lessonid" => $this->properties->id)); 01481 break; 01482 } 01483 } 01484 } 01485 if (!array_key_exists($exitjump, $lessonpages)) { 01486 return LESSON_EOL; 01487 } 01488 return $exitjump; 01489 } 01490 } 01491 } 01492 } 01493 01503 public function get_sub_pages_of($pageid, array $ends) { 01504 $lessonpages = $this->load_all_pages(); 01505 $pageid = $lessonpages[$pageid]->nextpageid; // move to the first page after the branch table 01506 $pages = array(); 01507 01508 while (true) { 01509 if ($pageid == 0 || in_array($lessonpages[$pageid]->qtype, $ends)) { 01510 break; 01511 } 01512 $pages[] = $lessonpages[$pageid]; 01513 $pageid = $lessonpages[$pageid]->nextpageid; 01514 } 01515 01516 return $pages; 01517 } 01518 01529 public function is_sub_page_of_type($pageid, array $types, array $ends) { 01530 $pages = $this->load_all_pages(); 01531 $pageid = $pages[$pageid]->prevpageid; // move up one 01532 01533 array_unshift($ends, 0); 01534 // go up the pages till branch table 01535 while (true) { 01536 if ($pageid==0 || in_array($pages[$pageid]->qtype, $ends)) { 01537 return false; 01538 } else if (in_array($pages[$pageid]->qtype, $types)) { 01539 return true; 01540 } 01541 $pageid = $pages[$pageid]->prevpageid; 01542 } 01543 } 01544 } 01545 01546 01560 abstract class lesson_base { 01561 01566 protected $properties; 01567 01572 public function __construct($properties) { 01573 $this->properties = (object)$properties; 01574 } 01575 01585 public function __set($key, $value) { 01586 if (method_exists($this, 'set_'.$key)) { 01587 $this->{'set_'.$key}($value); 01588 } 01589 $this->properties->{$key} = $value; 01590 } 01591 01601 public function __get($key) { 01602 if (method_exists($this, 'get_'.$key)) { 01603 return $this->{'get_'.$key}(); 01604 } 01605 return $this->properties->{$key}; 01606 } 01607 01615 public function __isset($key) { 01616 if (method_exists($this, 'get_'.$key)) { 01617 $val = $this->{'get_'.$key}(); 01618 return !empty($val); 01619 } 01620 return !empty($this->properties->{$key}); 01621 } 01622 01626 public static function create() {} 01630 public static function load() {} 01635 public function properties() { 01636 return $this->properties; 01637 } 01638 } 01639 01640 01678 abstract class lesson_page extends lesson_base { 01679 01684 protected $lesson = null; 01689 protected $answers = null; 01694 protected $type = 0; 01695 01699 const TYPE_QUESTION = 0; 01700 const TYPE_STRUCTURE = 1; 01701 01708 abstract protected function get_typeid(); 01714 abstract protected function get_typestring(); 01715 01723 abstract public function display($renderer, $attempt); 01724 01735 final public static function create($properties, lesson $lesson, $context, $maxbytes) { 01736 global $DB; 01737 $newpage = new stdClass; 01738 $newpage->title = $properties->title; 01739 $newpage->contents = $properties->contents_editor['text']; 01740 $newpage->contentsformat = $properties->contents_editor['format']; 01741 $newpage->lessonid = $lesson->id; 01742 $newpage->timecreated = time(); 01743 $newpage->qtype = $properties->qtype; 01744 $newpage->qoption = (isset($properties->qoption))?1:0; 01745 $newpage->layout = (isset($properties->layout))?1:0; 01746 $newpage->display = (isset($properties->display))?1:0; 01747 $newpage->prevpageid = 0; // this is a first page 01748 $newpage->nextpageid = 0; // this is the only page 01749 01750 if ($properties->pageid) { 01751 $prevpage = $DB->get_record("lesson_pages", array("id" => $properties->pageid), 'id, nextpageid'); 01752 if (!$prevpage) { 01753 print_error('cannotfindpages', 'lesson'); 01754 } 01755 $newpage->prevpageid = $prevpage->id; 01756 $newpage->nextpageid = $prevpage->nextpageid; 01757 } else { 01758 $nextpage = $DB->get_record('lesson_pages', array('lessonid'=>$lesson->id, 'prevpageid'=>0), 'id'); 01759 if ($nextpage) { 01760 // This is the first page, there are existing pages put this at the start 01761 $newpage->nextpageid = $nextpage->id; 01762 } 01763 } 01764 01765 $newpage->id = $DB->insert_record("lesson_pages", $newpage); 01766 01767 $editor = new stdClass; 01768 $editor->id = $newpage->id; 01769 $editor->contents_editor = $properties->contents_editor; 01770 $editor = file_postupdate_standard_editor($editor, 'contents', array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$maxbytes), $context, 'mod_lesson', 'page_contents', $editor->id); 01771 $DB->update_record("lesson_pages", $editor); 01772 01773 if ($newpage->prevpageid > 0) { 01774 $DB->set_field("lesson_pages", "nextpageid", $newpage->id, array("id" => $newpage->prevpageid)); 01775 } 01776 if ($newpage->nextpageid > 0) { 01777 $DB->set_field("lesson_pages", "prevpageid", $newpage->id, array("id" => $newpage->nextpageid)); 01778 } 01779 01780 $page = lesson_page::load($newpage, $lesson); 01781 $page->create_answers($properties); 01782 01783 $lesson->add_message(get_string('insertedpage', 'lesson').': '.format_string($newpage->title, true), 'notifysuccess'); 01784 01785 return $page; 01786 } 01787 01798 final public static function load($id, lesson $lesson) { 01799 global $DB; 01800 01801 if (is_object($id) && !empty($id->qtype)) { 01802 $page = $id; 01803 } else { 01804 $page = $DB->get_record("lesson_pages", array("id" => $id)); 01805 if (!$page) { 01806 print_error('cannotfindpages', 'lesson'); 01807 } 01808 } 01809 $manager = lesson_page_type_manager::get($lesson); 01810 01811 $class = 'lesson_page_type_'.$manager->get_page_type_idstring($page->qtype); 01812 if (!class_exists($class)) { 01813 $class = 'lesson_page'; 01814 } 01815 01816 return new $class($page, $lesson); 01817 } 01818 01824 final public function delete() { 01825 global $DB; 01826 // first delete all the associated records... 01827 $DB->delete_records("lesson_attempts", array("pageid" => $this->properties->id)); 01828 // ...now delete the answers... 01829 $DB->delete_records("lesson_answers", array("pageid" => $this->properties->id)); 01830 // ..and the page itself 01831 $DB->delete_records("lesson_pages", array("id" => $this->properties->id)); 01832 01833 // repair the hole in the linkage 01834 if (!$this->properties->prevpageid && !$this->properties->nextpageid) { 01835 //This is the only page, no repair needed 01836 } elseif (!$this->properties->prevpageid) { 01837 // this is the first page... 01838 $page = $this->lesson->load_page($this->properties->nextpageid); 01839 $page->move(null, 0); 01840 } elseif (!$this->properties->nextpageid) { 01841 // this is the last page... 01842 $page = $this->lesson->load_page($this->properties->prevpageid); 01843 $page->move(0); 01844 } else { 01845 // page is in the middle... 01846 $prevpage = $this->lesson->load_page($this->properties->prevpageid); 01847 $nextpage = $this->lesson->load_page($this->properties->nextpageid); 01848 01849 $prevpage->move($nextpage->id); 01850 $nextpage->move(null, $prevpage->id); 01851 } 01852 return true; 01853 } 01854 01863 final public function move($nextpageid=null, $prevpageid=null) { 01864 global $DB; 01865 if ($nextpageid === null) { 01866 $nextpageid = $this->properties->nextpageid; 01867 } 01868 if ($prevpageid === null) { 01869 $prevpageid = $this->properties->prevpageid; 01870 } 01871 $obj = new stdClass; 01872 $obj->id = $this->properties->id; 01873 $obj->prevpageid = $prevpageid; 01874 $obj->nextpageid = $nextpageid; 01875 $DB->update_record('lesson_pages', $obj); 01876 } 01877 01884 final public function get_answers() { 01885 global $DB; 01886 if ($this->answers === null) { 01887 $this->answers = array(); 01888 $answers = $DB->get_records('lesson_answers', array('pageid'=>$this->properties->id, 'lessonid'=>$this->lesson->id), 'id'); 01889 if (!$answers) { 01890 // It is possible that a lesson upgraded from Moodle 1.9 still 01891 // contains questions without any answers [MDL-25632]. 01892 // debugging(get_string('cannotfindanswer', 'lesson')); 01893 return array(); 01894 } 01895 foreach ($answers as $answer) { 01896 $this->answers[count($this->answers)] = new lesson_page_answer($answer); 01897 } 01898 } 01899 return $this->answers; 01900 } 01901 01907 final protected function get_lesson() { 01908 return $this->lesson; 01909 } 01910 01916 final protected function get_type() { 01917 return $this->type; 01918 } 01919 01928 final public function record_attempt($context) { 01929 global $DB, $USER, $OUTPUT; 01930 01935 $result = $this->check_answer(); 01936 01937 $result->attemptsremaining = 0; 01938 $result->maxattemptsreached = false; 01939 01940 if ($result->noanswer) { 01941 $result->newpageid = $this->properties->id; // display same page again 01942 $result->feedback = get_string('noanswer', 'lesson'); 01943 } else { 01944 if (!has_capability('mod/lesson:manage', $context)) { 01945 $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->lesson->id, "userid"=>$USER->id)); 01946 // record student's attempt 01947 $attempt = new stdClass; 01948 $attempt->lessonid = $this->lesson->id; 01949 $attempt->pageid = $this->properties->id; 01950 $attempt->userid = $USER->id; 01951 $attempt->answerid = $result->answerid; 01952 $attempt->retry = $nretakes; 01953 $attempt->correct = $result->correctanswer; 01954 if($result->userresponse !== null) { 01955 $attempt->useranswer = $result->userresponse; 01956 } 01957 01958 $attempt->timeseen = time(); 01959 // if allow modattempts, then update the old attempt record, otherwise, insert new answer record 01960 if (isset($USER->modattempts[$this->lesson->id])) { 01961 $attempt->retry = $nretakes - 1; // they are going through on review, $nretakes will be too high 01962 } 01963 01964 if ($this->lesson->retake || (!$this->lesson->retake && $nretakes == 0)) { 01965 $DB->insert_record("lesson_attempts", $attempt); 01966 } 01967 // "number of attempts remaining" message if $this->lesson->maxattempts > 1 01968 // displaying of message(s) is at the end of page for more ergonomic display 01969 if (!$result->correctanswer && ($result->newpageid == 0)) { 01970 // wrong answer and student is stuck on this page - check how many attempts 01971 // the student has had at this page/question 01972 $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $attempt->retry)); 01973 // retreive the number of attempts left counter for displaying at bottom of feedback page 01974 if ($nattempts >= $this->lesson->maxattempts) { 01975 if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt 01976 $result->maxattemptsreached = true; 01977 } 01978 $result->newpageid = LESSON_NEXTPAGE; 01979 } else if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt 01980 $result->attemptsremaining = $this->lesson->maxattempts - $nattempts; 01981 } 01982 } 01983 } 01984 // TODO: merge this code with the jump code below. Convert jumpto page into a proper page id 01985 if ($result->newpageid == 0) { 01986 $result->newpageid = $this->properties->id; 01987 } elseif ($result->newpageid == LESSON_NEXTPAGE) { 01988 $result->newpageid = $this->lesson->get_next_page($this->properties->nextpageid); 01989 } 01990 01991 // Determine default feedback if necessary 01992 if (empty($result->response)) { 01993 if (!$this->lesson->feedback && !$result->noanswer && !($this->lesson->review & !$result->correctanswer && !$result->isessayquestion)) { 01994 // These conditions have been met: 01995 // 1. The lesson manager has not supplied feedback to the student 01996 // 2. Not displaying default feedback 01997 // 3. The user did provide an answer 01998 // 4. We are not reviewing with an incorrect answer (and not reviewing an essay question) 01999 02000 $result->nodefaultresponse = true; // This will cause a redirect below 02001 } else if ($result->isessayquestion) { 02002 $result->response = get_string('defaultessayresponse', 'lesson'); 02003 } else if ($result->correctanswer) { 02004 $result->response = get_string('thatsthecorrectanswer', 'lesson'); 02005 } else { 02006 $result->response = get_string('thatsthewronganswer', 'lesson'); 02007 } 02008 } 02009 02010 if ($result->response) { 02011 if ($this->lesson->review && !$result->correctanswer && !$result->isessayquestion) { 02012 $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->lesson->id, "userid"=>$USER->id)); 02013 $qattempts = $DB->count_records("lesson_attempts", array("userid"=>$USER->id, "retry"=>$nretakes, "pageid"=>$this->properties->id)); 02014 if ($qattempts == 1) { 02015 $result->feedback = $OUTPUT->box(get_string("firstwrong", "lesson"), 'feedback'); 02016 } else { 02017 $result->feedback = $OUTPUT->BOX(get_string("secondpluswrong", "lesson"), 'feedback'); 02018 } 02019 } else { 02020 $class = 'response'; 02021 if ($result->correctanswer) { 02022 $class .= ' correct'; //CSS over-ride this if they exist (!important) 02023 } else if (!$result->isessayquestion) { 02024 $class .= ' incorrect'; //CSS over-ride this if they exist (!important) 02025 } 02026 $options = new stdClass; 02027 $options->noclean = true; 02028 $options->para = true; 02029 $options->overflowdiv = true; 02030 $result->feedback = $OUTPUT->box(format_text($this->get_contents(), $this->properties->contentsformat, $options), 'generalbox boxaligncenter'); 02031 $result->feedback .= '<div class="correctanswer generalbox"><em>'.get_string("youranswer", "lesson").'</em> : '.$result->studentanswer; // already in clean html 02032 $result->feedback .= $OUTPUT->box($result->response, $class); // already conerted to HTML 02033 $result->feedback .= '</div>'; 02034 } 02035 } 02036 } 02037 02038 return $result; 02039 } 02040 02048 final protected function get_jump_name($jumpto) { 02049 global $DB; 02050 static $jumpnames = array(); 02051 02052 if (!array_key_exists($jumpto, $jumpnames)) { 02053 if ($jumpto == LESSON_THISPAGE) { 02054 $jumptitle = get_string('thispage', 'lesson'); 02055 } elseif ($jumpto == LESSON_NEXTPAGE) { 02056 $jumptitle = get_string('nextpage', 'lesson'); 02057 } elseif ($jumpto == LESSON_EOL) { 02058 $jumptitle = get_string('endoflesson', 'lesson'); 02059 } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) { 02060 $jumptitle = get_string('unseenpageinbranch', 'lesson'); 02061 } elseif ($jumpto == LESSON_PREVIOUSPAGE) { 02062 $jumptitle = get_string('previouspage', 'lesson'); 02063 } elseif ($jumpto == LESSON_RANDOMPAGE) { 02064 $jumptitle = get_string('randompageinbranch', 'lesson'); 02065 } elseif ($jumpto == LESSON_RANDOMBRANCH) { 02066 $jumptitle = get_string('randombranch', 'lesson'); 02067 } elseif ($jumpto == LESSON_CLUSTERJUMP) { 02068 $jumptitle = get_string('clusterjump', 'lesson'); 02069 } else { 02070 if (!$jumptitle = $DB->get_field('lesson_pages', 'title', array('id' => $jumpto))) { 02071 $jumptitle = '<strong>'.get_string('notdefined', 'lesson').'</strong>'; 02072 } 02073 } 02074 $jumpnames[$jumpto] = format_string($jumptitle,true); 02075 } 02076 02077 return $jumpnames[$jumpto]; 02078 } 02079 02085 public function __construct($properties, lesson $lesson) { 02086 parent::__construct($properties); 02087 $this->lesson = $lesson; 02088 } 02089 02097 public function earned_score($answers, $attempt) { 02098 return $answers[$attempt->answerid]->score; 02099 } 02100 02108 public function callback_on_view($canmanage) { 02109 return true; 02110 } 02111 02118 public function update($properties, $context = null, $maxbytes = null) { 02119 global $DB, $PAGE; 02120 $answers = $this->get_answers(); 02121 $properties->id = $this->properties->id; 02122 $properties->lessonid = $this->lesson->id; 02123 if (empty($properties->qoption)) { 02124 $properties->qoption = '0'; 02125 } 02126 if (empty($context)) { 02127 $context = $PAGE->context; 02128 } 02129 if ($maxbytes === null) { 02130 $maxbytes =get_max_upload_file_size(); 02131 } 02132 $properties = file_postupdate_standard_editor($properties, 'contents', array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$maxbytes), $context, 'mod_lesson', 'page_contents', $properties->id); 02133 $DB->update_record("lesson_pages", $properties); 02134 02135 for ($i = 0; $i < $this->lesson->maxanswers; $i++) { 02136 if (!array_key_exists($i, $this->answers)) { 02137 $this->answers[$i] = new stdClass; 02138 $this->answers[$i]->lessonid = $this->lesson->id; 02139 $this->answers[$i]->pageid = $this->id; 02140 $this->answers[$i]->timecreated = $this->timecreated; 02141 } 02142 02143 if (!empty($properties->answer_editor[$i]) && is_array($properties->answer_editor[$i])) { 02144 $this->answers[$i]->answer = $properties->answer_editor[$i]['text']; 02145 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format']; 02146 } 02147 if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) { 02148 $this->answers[$i]->response = $properties->response_editor[$i]['text']; 02149 $this->answers[$i]->responseformat = $properties->response_editor[$i]['format']; 02150 } 02151 02152 // we don't need to check for isset here because properties called it's own isset method. 02153 if ($this->answers[$i]->answer != '') { 02154 if (isset($properties->jumpto[$i])) { 02155 $this->answers[$i]->jumpto = $properties->jumpto[$i]; 02156 } 02157 if ($this->lesson->custom && isset($properties->score[$i])) { 02158 $this->answers[$i]->score = $properties->score[$i]; 02159 } 02160 if (!isset($this->answers[$i]->id)) { 02161 $this->answers[$i]->id = $DB->insert_record("lesson_answers", $this->answers[$i]); 02162 } else { 02163 $DB->update_record("lesson_answers", $this->answers[$i]->properties()); 02164 } 02165 02166 } else if (isset($this->answers[$i]->id)) { 02167 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id)); 02168 unset($this->answers[$i]); 02169 } 02170 } 02171 return true; 02172 } 02173 02180 public function add_page_link($previd) { 02181 return false; 02182 } 02183 02191 public function is_unseen($param) { 02192 global $USER, $DB; 02193 if (is_array($param)) { 02194 $seenpages = $param; 02195 return (!array_key_exists($this->properties->id, $seenpages)); 02196 } else { 02197 $nretakes = $param; 02198 if (!$DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry"=>$nretakes))) { 02199 return true; 02200 } 02201 } 02202 return false; 02203 } 02204 02210 public function is_unanswered($nretakes) { 02211 global $DB, $USER; 02212 if (!$DB->count_records("lesson_attempts", array('pageid'=>$this->properties->id, 'userid'=>$USER->id, 'correct'=>1, 'retry'=>$nretakes))) { 02213 return true; 02214 } 02215 return false; 02216 } 02217 02224 public function create_answers($properties) { 02225 global $DB; 02226 // now add the answers 02227 $newanswer = new stdClass; 02228 $newanswer->lessonid = $this->lesson->id; 02229 $newanswer->pageid = $this->properties->id; 02230 $newanswer->timecreated = $this->properties->timecreated; 02231 02232 $answers = array(); 02233 02234 for ($i = 0; $i < $this->lesson->maxanswers; $i++) { 02235 $answer = clone($newanswer); 02236 02237 if (!empty($properties->answer_editor[$i]) && is_array($properties->answer_editor[$i])) { 02238 $answer->answer = $properties->answer_editor[$i]['text']; 02239 $answer->answerformat = $properties->answer_editor[$i]['format']; 02240 } 02241 if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) { 02242 $answer->response = $properties->response_editor[$i]['text']; 02243 $answer->responseformat = $properties->response_editor[$i]['format']; 02244 } 02245 02246 if (isset($answer->answer) && $answer->answer != '') { 02247 if (isset($properties->jumpto[$i])) { 02248 $answer->jumpto = $properties->jumpto[$i]; 02249 } 02250 if ($this->lesson->custom && isset($properties->score[$i])) { 02251 $answer->score = $properties->score[$i]; 02252 } 02253 $answer->id = $DB->insert_record("lesson_answers", $answer); 02254 $answers[$answer->id] = new lesson_page_answer($answer); 02255 } else { 02256 break; 02257 } 02258 } 02259 02260 $this->answers = $answers; 02261 return $answers; 02262 } 02263 02277 public function check_answer() { 02278 $result = new stdClass; 02279 $result->answerid = 0; 02280 $result->noanswer = false; 02281 $result->correctanswer = false; 02282 $result->isessayquestion = false; // use this to turn off review button on essay questions 02283 $result->response = ''; 02284 $result->newpageid = 0; // stay on the page 02285 $result->studentanswer = ''; // use this to store student's answer(s) in order to display it on feedback page 02286 $result->userresponse = null; 02287 $result->feedback = ''; 02288 $result->nodefaultresponse = false; // Flag for redirecting when default feedback is turned off 02289 return $result; 02290 } 02291 02299 public function has_option() { 02300 return false; 02301 } 02302 02310 public function max_answers($default) { 02311 return $default; 02312 } 02313 02318 public function properties() { 02319 $properties = clone($this->properties); 02320 if ($this->answers === null) { 02321 $this->get_answers(); 02322 } 02323 if (count($this->answers)>0) { 02324 $count = 0; 02325 foreach ($this->answers as $answer) { 02326 $properties->{'answer_editor['.$count.']'} = array('text'=>$answer->answer, 'format'=>$answer->answerformat); 02327 $properties->{'response_editor['.$count.']'} = array('text'=>$answer->response, 'format'=>$answer->responseformat); 02328 $properties->{'jumpto['.$count.']'} = $answer->jumpto; 02329 $properties->{'score['.$count.']'} = $answer->score; 02330 $count++; 02331 } 02332 } 02333 return $properties; 02334 } 02335 02343 public static function get_jumptooptions($pageid, lesson $lesson) { 02344 global $DB; 02345 $jump = array(); 02346 $jump[0] = get_string("thispage", "lesson"); 02347 $jump[LESSON_NEXTPAGE] = get_string("nextpage", "lesson"); 02348 $jump[LESSON_PREVIOUSPAGE] = get_string("previouspage", "lesson"); 02349 $jump[LESSON_EOL] = get_string("endoflesson", "lesson"); 02350 02351 if ($pageid == 0) { 02352 return $jump; 02353 } 02354 02355 $pages = $lesson->load_all_pages(); 02356 if ($pages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE || $lesson->is_sub_page_of_type($pageid, array(LESSON_PAGE_BRANCHTABLE), array(LESSON_PAGE_ENDOFBRANCH, LESSON_PAGE_CLUSTER))) { 02357 $jump[LESSON_UNSEENBRANCHPAGE] = get_string("unseenpageinbranch", "lesson"); 02358 $jump[LESSON_RANDOMPAGE] = get_string("randompageinbranch", "lesson"); 02359 } 02360 if($pages[$pageid]->qtype == LESSON_PAGE_CLUSTER || $lesson->is_sub_page_of_type($pageid, array(LESSON_PAGE_CLUSTER), array(LESSON_PAGE_ENDOFCLUSTER))) { 02361 $jump[LESSON_CLUSTERJUMP] = get_string("clusterjump", "lesson"); 02362 } 02363 if (!optional_param('firstpage', 0, PARAM_INT)) { 02364 $apageid = $DB->get_field("lesson_pages", "id", array("lessonid" => $lesson->id, "prevpageid" => 0)); 02365 while (true) { 02366 if ($apageid) { 02367 $title = $DB->get_field("lesson_pages", "title", array("id" => $apageid)); 02368 $jump[$apageid] = strip_tags(format_string($title,true)); 02369 $apageid = $DB->get_field("lesson_pages", "nextpageid", array("id" => $apageid)); 02370 } else { 02371 // last page reached 02372 break; 02373 } 02374 } 02375 } 02376 return $jump; 02377 } 02383 public function get_contents() { 02384 global $PAGE; 02385 if (!empty($this->properties->contents)) { 02386 if (!isset($this->properties->contentsformat)) { 02387 $this->properties->contentsformat = FORMAT_HTML; 02388 } 02389 $context = get_context_instance(CONTEXT_MODULE, $PAGE->cm->id); 02390 $contents = file_rewrite_pluginfile_urls($this->properties->contents, 'pluginfile.php', $context->id, 'mod_lesson', 'page_contents', $this->properties->id); // must do this BEFORE format_text()!!!!!! 02391 return format_text($contents, $this->properties->contentsformat, array('context'=>$context, 'noclean'=>true)); // page edit is marked with XSS, we want all content here 02392 } else { 02393 return ''; 02394 } 02395 } 02396 02401 protected function get_displayinmenublock() { 02402 return false; 02403 } 02404 02409 public function option_description_string() { 02410 return ''; 02411 } 02412 02418 public function display_answers(html_table $table) { 02419 $answers = $this->get_answers(); 02420 $i = 1; 02421 foreach ($answers as $answer) { 02422 $cells = array(); 02423 $cells[] = "<span class=\"label\">".get_string("jump", "lesson")." $i<span>: "; 02424 $cells[] = $this->get_jump_name($answer->jumpto); 02425 $table->data[] = new html_table_row($cells); 02426 if ($i === 1){ 02427 $table->data[count($table->data)-1]->cells[0]->style = 'width:20%;'; 02428 } 02429 $i++; 02430 } 02431 return $table; 02432 } 02433 02438 protected function get_grayout() { 02439 return 0; 02440 } 02441 02449 public function stats(array &$pagestats, $tries) { 02450 return true; 02451 } 02452 02464 public function report_answers($answerpage, $answerdata, $useranswer, $pagestats, &$i, &$n) { 02465 $answers = $this->get_answers(); 02466 $formattextdefoptions = new stdClass; 02467 $formattextdefoptions->para = false; //I'll use it widely in this page 02468 foreach ($answers as $answer) { 02469 $data = get_string('jumpsto', 'lesson', $this->get_jump_name($answer->jumpto)); 02470 $answerdata->answers[] = array($data, ""); 02471 $answerpage->answerdata = $answerdata; 02472 } 02473 return $answerpage; 02474 } 02475 02481 public function get_jumps() { 02482 global $DB; 02483 $jumps = array(); 02484 $params = array ("lessonid" => $this->lesson->id, "pageid" => $this->properties->id); 02485 if ($answers = $this->get_answers()) { 02486 foreach ($answers as $answer) { 02487 $jumps[] = $this->get_jump_name($answer->jumpto); 02488 } 02489 } else { 02490 $jumps[] = $this->get_jump_name($this->properties->nextpageid); 02491 } 02492 return $jumps; 02493 } 02498 public function requires_manual_grading() { 02499 return false; 02500 } 02501 02507 public function override_next_page() { 02508 return false; 02509 } 02510 02518 public function valid_page_and_view(&$validpages, &$pageviews) { 02519 $validpages[$this->properties->id] = 1; 02520 return $this->properties->nextpageid; 02521 } 02522 } 02523 02524 02525 02544 class lesson_page_answer extends lesson_base { 02545 02552 public static function load($id) { 02553 global $DB; 02554 $answer = $DB->get_record("lesson_answers", array("id" => $id)); 02555 return new lesson_page_answer($answer); 02556 } 02557 02566 public static function create($properties, lesson_page $page) { 02567 return $page->create_answers($properties); 02568 } 02569 02570 } 02571 02586 class lesson_page_type_manager { 02587 02592 protected $types = array(); 02593 02603 public static function get(lesson $lesson) { 02604 static $pagetypemanager; 02605 if (!($pagetypemanager instanceof lesson_page_type_manager)) { 02606 $pagetypemanager = new lesson_page_type_manager(); 02607 $pagetypemanager->load_lesson_types($lesson); 02608 } 02609 return $pagetypemanager; 02610 } 02611 02617 public function load_lesson_types(lesson $lesson) { 02618 global $CFG; 02619 $basedir = $CFG->dirroot.'/mod/lesson/pagetypes/'; 02620 $dir = dir($basedir); 02621 while (false !== ($entry = $dir->read())) { 02622 if (strpos($entry, '.')===0 || !preg_match('#^[a-zA-Z]+\.php#i', $entry)) { 02623 continue; 02624 } 02625 require_once($basedir.$entry); 02626 $class = 'lesson_page_type_'.strtok($entry,'.'); 02627 if (class_exists($class)) { 02628 $pagetype = new $class(new stdClass, $lesson); 02629 $this->types[$pagetype->typeid] = $pagetype; 02630 } 02631 } 02632 02633 } 02634 02641 public function get_page_type_strings($type=null, $special=true) { 02642 $types = array(); 02643 foreach ($this->types as $pagetype) { 02644 if (($type===null || $pagetype->type===$type) && ($special===true || $pagetype->is_standard())) { 02645 $types[$pagetype->typeid] = $pagetype->typestring; 02646 } 02647 } 02648 return $types; 02649 } 02650 02660 public function get_page_type_idstring($id) { 02661 foreach ($this->types as $pagetype) { 02662 if ((int)$pagetype->typeid === (int)$id) { 02663 return $pagetype->idstring; 02664 } 02665 } 02666 return 'unknown'; 02667 } 02668 02680 public function load_page($pageid, lesson $lesson) { 02681 global $DB; 02682 if (!($page =$DB->get_record('lesson_pages', array('id'=>$pageid, 'lessonid'=>$lesson->id)))) { 02683 print_error('cannotfindpages', 'lesson'); 02684 } 02685 $pagetype = get_class($this->types[$page->qtype]); 02686 $page = new $pagetype($page, $lesson); 02687 return $page; 02688 } 02689 02696 public function load_all_pages(lesson $lesson) { 02697 global $DB; 02698 if (!($pages =$DB->get_records('lesson_pages', array('lessonid'=>$lesson->id)))) { 02699 print_error('cannotfindpages', 'lesson'); 02700 } 02701 foreach ($pages as $key=>$page) { 02702 $pagetype = get_class($this->types[$page->qtype]); 02703 $pages[$key] = new $pagetype($page, $lesson); 02704 } 02705 02706 $orderedpages = array(); 02707 $lastpageid = 0; 02708 02709 while (true) { 02710 foreach ($pages as $page) { 02711 if ((int)$page->prevpageid === (int)$lastpageid) { 02712 $orderedpages[$page->id] = $page; 02713 unset($pages[$page->id]); 02714 $lastpageid = $page->id; 02715 if ((int)$page->nextpageid===0) { 02716 break 2; 02717 } else { 02718 break 1; 02719 } 02720 } 02721 } 02722 } 02723 02724 return $orderedpages; 02725 } 02726 02734 public function get_page_form($type, $arguments) { 02735 $class = 'lesson_add_page_form_'.$this->get_page_type_idstring($type); 02736 if (!class_exists($class) || get_parent_class($class)!=='lesson_add_page_form_base') { 02737 debugging('Lesson page type unknown class requested '.$class, DEBUG_DEVELOPER); 02738 $class = 'lesson_add_page_form_selection'; 02739 } else if ($class === 'lesson_add_page_form_unknown') { 02740 $class = 'lesson_add_page_form_selection'; 02741 } 02742 return new $class(null, $arguments); 02743 } 02744 02750 public function get_add_page_type_links($previd) { 02751 global $OUTPUT; 02752 02753 $links = array(); 02754 02755 foreach ($this->types as $key=>$type) { 02756 if ($link = $type->add_page_link($previd)) { 02757 $links[$key] = $link; 02758 } 02759 } 02760 02761 return $links; 02762 } 02763 }