Differences Between: [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Book module core interaction API 19 * 20 * @package mod_book 21 * @copyright 2004-2011 Petr Skoda {@link http://skodak.org} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die; 26 27 /** 28 * Returns list of available numbering types 29 * @return array 30 */ 31 function book_get_numbering_types() { 32 global $CFG; // required for the include 33 34 require_once (__DIR__.'/locallib.php'); 35 36 return array ( 37 BOOK_NUM_NONE => get_string('numbering0', 'mod_book'), 38 BOOK_NUM_NUMBERS => get_string('numbering1', 'mod_book'), 39 BOOK_NUM_BULLETS => get_string('numbering2', 'mod_book'), 40 BOOK_NUM_INDENTED => get_string('numbering3', 'mod_book') 41 ); 42 } 43 44 /** 45 * Returns list of available navigation link types. 46 * @return array 47 */ 48 function book_get_nav_types() { 49 require_once (__DIR__.'/locallib.php'); 50 51 return array ( 52 BOOK_LINK_TOCONLY => get_string('navtoc', 'mod_book'), 53 BOOK_LINK_IMAGE => get_string('navimages', 'mod_book'), 54 BOOK_LINK_TEXT => get_string('navtext', 'mod_book'), 55 ); 56 } 57 58 /** 59 * Returns list of available navigation link CSS classes. 60 * @return array 61 */ 62 function book_get_nav_classes() { 63 return array ('navtoc', 'navimages', 'navtext'); 64 } 65 66 /** 67 * Add book instance. 68 * 69 * @param stdClass $data 70 * @param stdClass $mform 71 * @return int new book instance id 72 */ 73 function book_add_instance($data, $mform) { 74 global $DB; 75 76 $data->timecreated = time(); 77 $data->timemodified = $data->timecreated; 78 if (!isset($data->customtitles)) { 79 $data->customtitles = 0; 80 } 81 82 $id = $DB->insert_record('book', $data); 83 84 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 85 \core_completion\api::update_completion_date_event($data->coursemodule, 'book', $id, $completiontimeexpected); 86 87 return $id; 88 } 89 90 /** 91 * Update book instance. 92 * 93 * @param stdClass $data 94 * @param stdClass $mform 95 * @return bool true 96 */ 97 function book_update_instance($data, $mform) { 98 global $DB; 99 100 $data->timemodified = time(); 101 $data->id = $data->instance; 102 if (!isset($data->customtitles)) { 103 $data->customtitles = 0; 104 } 105 106 $DB->update_record('book', $data); 107 108 $book = $DB->get_record('book', array('id'=>$data->id)); 109 $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id)); 110 111 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 112 \core_completion\api::update_completion_date_event($data->coursemodule, 'book', $book->id, $completiontimeexpected); 113 114 return true; 115 } 116 117 /** 118 * Delete book instance by activity id 119 * 120 * @param int $id 121 * @return bool success 122 */ 123 function book_delete_instance($id) { 124 global $DB; 125 126 if (!$book = $DB->get_record('book', array('id'=>$id))) { 127 return false; 128 } 129 130 $cm = get_coursemodule_from_instance('book', $id); 131 \core_completion\api::update_completion_date_event($cm->id, 'book', $id, null); 132 133 $DB->delete_records('book_chapters', array('bookid'=>$book->id)); 134 $DB->delete_records('book', array('id'=>$book->id)); 135 136 return true; 137 } 138 139 /** 140 * Given a course and a time, this module should find recent activity 141 * that has occurred in book activities and print it out. 142 * 143 * @param stdClass $course 144 * @param bool $viewfullnames 145 * @param int $timestart 146 * @return bool true if there was output, or false is there was none 147 */ 148 function book_print_recent_activity($course, $viewfullnames, $timestart) { 149 return false; // True if anything was printed, otherwise false 150 } 151 152 /** 153 * This function is used by the reset_course_userdata function in moodlelib. 154 * @param $data the data submitted from the reset course. 155 * @return array status array 156 */ 157 function book_reset_userdata($data) { 158 global $DB; 159 // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. 160 // See MDL-9367. 161 162 $status = []; 163 164 if (!empty($data->reset_book_tags)) { 165 // Loop through the books and remove the tags from the chapters. 166 if ($books = $DB->get_records('book', array('course' => $data->courseid))) { 167 foreach ($books as $book) { 168 if (!$cm = get_coursemodule_from_instance('book', $book->id)) { 169 continue; 170 } 171 172 $context = context_module::instance($cm->id); 173 core_tag_tag::delete_instances('mod_book', null, $context->id); 174 } 175 } 176 177 178 $status[] = [ 179 'component' => get_string('modulenameplural', 'book'), 180 'item' => get_string('tagsdeleted', 'book'), 181 'error' => false 182 ]; 183 } 184 185 return $status; 186 } 187 188 /** 189 * The elements to add the course reset form. 190 * 191 * @param moodleform $mform 192 */ 193 function book_reset_course_form_definition(&$mform) { 194 $mform->addElement('header', 'bookheader', get_string('modulenameplural', 'book')); 195 $mform->addElement('checkbox', 'reset_book_tags', get_string('removeallbooktags', 'book')); 196 } 197 198 /** 199 * No cron in book. 200 * 201 * @return bool 202 */ 203 function book_cron () { 204 return true; 205 } 206 207 /** 208 * No grading in book. 209 * 210 * @param int $bookid 211 * @return null 212 */ 213 function book_grades($bookid) { 214 return null; 215 } 216 217 /** 218 * @deprecated since Moodle 3.8 219 */ 220 function book_scale_used() { 221 throw new coding_exception('book_scale_used() can not be used anymore. Plugins can implement ' . 222 '<modname>_scale_used_anywhere, all implementations of <modname>_scale_used are now ignored'); 223 } 224 225 /** 226 * Checks if scale is being used by any instance of book 227 * 228 * This is used to find out if scale used anywhere 229 * 230 * @param int $scaleid 231 * @return bool true if the scale is used by any book 232 */ 233 function book_scale_used_anywhere($scaleid) { 234 return false; 235 } 236 237 /** 238 * Return read actions. 239 * 240 * Note: This is not used by new logging system. Event with 241 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will 242 * be considered as view action. 243 * 244 * @return array 245 */ 246 function book_get_view_actions() { 247 global $CFG; // necessary for includes 248 249 $return = array('view', 'view all'); 250 251 $plugins = core_component::get_plugin_list('booktool'); 252 foreach ($plugins as $plugin => $dir) { 253 if (file_exists("$dir/lib.php")) { 254 require_once("$dir/lib.php"); 255 } 256 $function = 'booktool_'.$plugin.'_get_view_actions'; 257 if (function_exists($function)) { 258 if ($actions = $function()) { 259 $return = array_merge($return, $actions); 260 } 261 } 262 } 263 264 return $return; 265 } 266 267 /** 268 * Return write actions. 269 * 270 * Note: This is not used by new logging system. Event with 271 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING 272 * will be considered as post action. 273 * 274 * @return array 275 */ 276 function book_get_post_actions() { 277 global $CFG; // necessary for includes 278 279 $return = array('update'); 280 281 $plugins = core_component::get_plugin_list('booktool'); 282 foreach ($plugins as $plugin => $dir) { 283 if (file_exists("$dir/lib.php")) { 284 require_once("$dir/lib.php"); 285 } 286 $function = 'booktool_'.$plugin.'_get_post_actions'; 287 if (function_exists($function)) { 288 if ($actions = $function()) { 289 $return = array_merge($return, $actions); 290 } 291 } 292 } 293 294 return $return; 295 } 296 297 /** 298 * Supported features 299 * 300 * @param string $feature FEATURE_xx constant for requested feature 301 * @return mixed True if module supports feature, false if not, null if doesn't know 302 */ 303 function book_supports($feature) { 304 switch($feature) { 305 case FEATURE_MOD_ARCHETYPE: return MOD_ARCHETYPE_RESOURCE; 306 case FEATURE_GROUPS: return false; 307 case FEATURE_GROUPINGS: return false; 308 case FEATURE_MOD_INTRO: return true; 309 case FEATURE_COMPLETION_TRACKS_VIEWS: return true; 310 case FEATURE_GRADE_HAS_GRADE: return false; 311 case FEATURE_GRADE_OUTCOMES: return false; 312 case FEATURE_BACKUP_MOODLE2: return true; 313 case FEATURE_SHOW_DESCRIPTION: return true; 314 315 default: return null; 316 } 317 } 318 319 /** 320 * Adds module specific settings to the settings block 321 * 322 * @param settings_navigation $settingsnav The settings navigation object 323 * @param navigation_node $booknode The node to add module settings to 324 * @return void 325 */ 326 function book_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $booknode) { 327 global $USER, $PAGE, $OUTPUT; 328 329 if ($booknode->children->count() > 0) { 330 $firstkey = $booknode->children->get_key_list()[0]; 331 } else { 332 $firstkey = null; 333 } 334 335 $params = $PAGE->url->params(); 336 337 if ($PAGE->cm->modname === 'book' and !empty($params['id']) and !empty($params['chapterid']) 338 and has_capability('mod/book:edit', $PAGE->cm->context)) { 339 if (!empty($USER->editing)) { 340 $string = get_string("turneditingoff"); 341 $edit = '0'; 342 } else { 343 $string = get_string("turneditingon"); 344 $edit = '1'; 345 } 346 $url = new moodle_url('/mod/book/view.php', array('id'=>$params['id'], 'chapterid'=>$params['chapterid'], 'edit'=>$edit, 'sesskey'=>sesskey())); 347 $editnode = navigation_node::create($string, $url, navigation_node::TYPE_SETTING); 348 $booknode->add_node($editnode, $firstkey); 349 $PAGE->set_button($OUTPUT->single_button($url, $string)); 350 } 351 352 $plugins = core_component::get_plugin_list('booktool'); 353 foreach ($plugins as $plugin => $dir) { 354 if (file_exists("$dir/lib.php")) { 355 require_once("$dir/lib.php"); 356 } 357 $function = 'booktool_'.$plugin.'_extend_settings_navigation'; 358 if (function_exists($function)) { 359 $function($settingsnav, $booknode); 360 } 361 } 362 } 363 364 365 /** 366 * Lists all browsable file areas 367 * @param object $course 368 * @param object $cm 369 * @param object $context 370 * @return array 371 */ 372 function book_get_file_areas($course, $cm, $context) { 373 $areas = array(); 374 $areas['chapter'] = get_string('chapters', 'mod_book'); 375 return $areas; 376 } 377 378 /** 379 * File browsing support for book module chapter area. 380 * @param object $browser 381 * @param object $areas 382 * @param object $course 383 * @param object $cm 384 * @param object $context 385 * @param string $filearea 386 * @param int $itemid 387 * @param string $filepath 388 * @param string $filename 389 * @return object file_info instance or null if not found 390 */ 391 function book_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { 392 global $CFG, $DB; 393 394 // note: 'intro' area is handled in file_browser automatically 395 396 if (!has_capability('mod/book:read', $context)) { 397 return null; 398 } 399 400 if ($filearea !== 'chapter') { 401 return null; 402 } 403 404 require_once (__DIR__.'/locallib.php'); 405 406 if (is_null($itemid)) { 407 return new book_file_info($browser, $course, $cm, $context, $areas, $filearea); 408 } 409 410 $fs = get_file_storage(); 411 $filepath = is_null($filepath) ? '/' : $filepath; 412 $filename = is_null($filename) ? '.' : $filename; 413 if (!$storedfile = $fs->get_file($context->id, 'mod_book', $filearea, $itemid, $filepath, $filename)) { 414 return null; 415 } 416 417 // modifications may be tricky - may cause caching problems 418 $canwrite = has_capability('mod/book:edit', $context); 419 420 $chaptername = $DB->get_field('book_chapters', 'title', array('bookid'=>$cm->instance, 'id'=>$itemid)); 421 $chaptername = format_string($chaptername, true, array('context'=>$context)); 422 423 $urlbase = $CFG->wwwroot.'/pluginfile.php'; 424 return new file_info_stored($browser, $context, $storedfile, $urlbase, $chaptername, true, true, $canwrite, false); 425 } 426 427 /** 428 * Serves the book attachments. Implements needed access control ;-) 429 * 430 * @param stdClass $course course object 431 * @param cm_info $cm course module object 432 * @param context $context context object 433 * @param string $filearea file area 434 * @param array $args extra arguments 435 * @param bool $forcedownload whether or not force download 436 * @param array $options additional options affecting the file serving 437 * @return bool false if file not found, does not return if found - just send the file 438 */ 439 function book_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) { 440 global $CFG, $DB; 441 442 if ($context->contextlevel != CONTEXT_MODULE) { 443 return false; 444 } 445 446 require_course_login($course, true, $cm); 447 448 if ($filearea !== 'chapter') { 449 return false; 450 } 451 452 if (!has_capability('mod/book:read', $context)) { 453 return false; 454 } 455 456 $chid = (int)array_shift($args); 457 458 if (!$book = $DB->get_record('book', array('id'=>$cm->instance))) { 459 return false; 460 } 461 462 if (!$chapter = $DB->get_record('book_chapters', array('id'=>$chid, 'bookid'=>$book->id))) { 463 return false; 464 } 465 466 if ($chapter->hidden and !has_capability('mod/book:viewhiddenchapters', $context)) { 467 return false; 468 } 469 470 // Download the contents of a chapter as an html file. 471 if ($args[0] == 'index.html') { 472 $filename = "index.html"; 473 474 // We need to rewrite the pluginfile URLs so the media filters can work. 475 $content = file_rewrite_pluginfile_urls($chapter->content, 'webservice/pluginfile.php', $context->id, 'mod_book', 'chapter', 476 $chapter->id); 477 $formatoptions = new stdClass; 478 $formatoptions->noclean = true; 479 $formatoptions->overflowdiv = true; 480 $formatoptions->context = $context; 481 482 $content = format_text($content, $chapter->contentformat, $formatoptions); 483 484 // Remove @@PLUGINFILE@@/. 485 $options = array('reverse' => true); 486 $content = file_rewrite_pluginfile_urls($content, 'webservice/pluginfile.php', $context->id, 'mod_book', 'chapter', 487 $chapter->id, $options); 488 $content = str_replace('@@PLUGINFILE@@/', '', $content); 489 490 $titles = ""; 491 // Format the chapter titles. 492 if (!$book->customtitles) { 493 require_once (__DIR__.'/locallib.php'); 494 $chapters = book_preload_chapters($book); 495 496 if (!$chapter->subchapter) { 497 $currtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context); 498 // Note that we can't use the $OUTPUT->heading() in WS_SERVER mode. 499 $titles = "<h3>$currtitle</h3>"; 500 } else { 501 $currtitle = book_get_chapter_title($chapters[$chapter->id]->parent, $chapters, $book, $context); 502 $currsubtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context); 503 // Note that we can't use the $OUTPUT->heading() in WS_SERVER mode. 504 $titles = "<h3>$currtitle</h3>"; 505 $titles .= "<h4>$currsubtitle</h4>"; 506 } 507 } 508 509 $content = $titles . $content; 510 511 send_file($content, $filename, 0, 0, true, true); 512 } else { 513 $fs = get_file_storage(); 514 $relativepath = implode('/', $args); 515 $fullpath = "/$context->id/mod_book/chapter/$chid/$relativepath"; 516 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 517 return false; 518 } 519 520 // Nasty hack because we do not have file revisions in book yet. 521 $lifetime = $CFG->filelifetime; 522 if ($lifetime > 60 * 10) { 523 $lifetime = 60 * 10; 524 } 525 526 // Finally send the file. 527 send_stored_file($file, $lifetime, 0, $forcedownload, $options); 528 } 529 } 530 531 /** 532 * Return a list of page types 533 * 534 * @param string $pagetype current page type 535 * @param stdClass $parentcontext Block's parent context 536 * @param stdClass $currentcontext Current context of block 537 * @return array 538 */ 539 function book_page_type_list($pagetype, $parentcontext, $currentcontext) { 540 $module_pagetype = array('mod-book-*'=>get_string('page-mod-book-x', 'mod_book')); 541 return $module_pagetype; 542 } 543 544 /** 545 * Export book resource contents 546 * 547 * @param stdClass $cm Course module object 548 * @param string $baseurl Base URL for file downloads 549 * @return array of file content 550 */ 551 function book_export_contents($cm, $baseurl) { 552 global $DB; 553 554 $contents = array(); 555 $context = context_module::instance($cm->id); 556 557 $book = $DB->get_record('book', array('id' => $cm->instance), '*', MUST_EXIST); 558 559 $fs = get_file_storage(); 560 561 $chapters = $DB->get_records('book_chapters', array('bookid' => $book->id), 'pagenum'); 562 563 $structure = array(); 564 $currentchapter = 0; 565 566 foreach ($chapters as $chapter) { 567 if ($chapter->hidden && !has_capability('mod/book:viewhiddenchapters', $context)) { 568 continue; 569 } 570 571 // Generate the book structure. 572 $thischapter = array( 573 "title" => format_string($chapter->title, true, array('context' => $context)), 574 "href" => $chapter->id . "/index.html", 575 "level" => 0, 576 "hidden" => $chapter->hidden, 577 "subitems" => array() 578 ); 579 580 // Main chapter. 581 if (!$chapter->subchapter) { 582 $currentchapter = $chapter->pagenum; 583 $structure[$currentchapter] = $thischapter; 584 } else { 585 // Subchapter. 586 $thischapter['level'] = 1; 587 $structure[$currentchapter]["subitems"][] = $thischapter; 588 } 589 590 // Export the chapter contents. 591 592 // Main content (html). 593 $filename = 'index.html'; 594 $chapterindexfile = array(); 595 $chapterindexfile['type'] = 'file'; 596 $chapterindexfile['filename'] = $filename; 597 // Each chapter in a subdirectory. 598 $chapterindexfile['filepath'] = "/{$chapter->id}/"; 599 $chapterindexfile['filesize'] = 0; 600 $chapterindexfile['fileurl'] = moodle_url::make_webservice_pluginfile_url( 601 $context->id, 'mod_book', 'chapter', $chapter->id, '/', 'index.html')->out(false); 602 $chapterindexfile['timecreated'] = $chapter->timecreated; 603 $chapterindexfile['timemodified'] = $chapter->timemodified; 604 $chapterindexfile['content'] = format_string($chapter->title, true, array('context' => $context)); 605 $chapterindexfile['sortorder'] = 0; 606 $chapterindexfile['userid'] = null; 607 $chapterindexfile['author'] = null; 608 $chapterindexfile['license'] = null; 609 $chapterindexfile['tags'] = \core_tag\external\util::get_item_tags('mod_book', 'book_chapters', $chapter->id); 610 $contents[] = $chapterindexfile; 611 612 // Chapter files (images usually). 613 $files = $fs->get_area_files($context->id, 'mod_book', 'chapter', $chapter->id, 'sortorder DESC, id ASC', false); 614 foreach ($files as $fileinfo) { 615 $file = array(); 616 $file['type'] = 'file'; 617 $file['filename'] = $fileinfo->get_filename(); 618 $file['filepath'] = "/{$chapter->id}" . $fileinfo->get_filepath(); 619 $file['filesize'] = $fileinfo->get_filesize(); 620 $file['fileurl'] = moodle_url::make_webservice_pluginfile_url( 621 $context->id, 'mod_book', 'chapter', $chapter->id, 622 $fileinfo->get_filepath(), $fileinfo->get_filename())->out(false); 623 $file['timecreated'] = $fileinfo->get_timecreated(); 624 $file['timemodified'] = $fileinfo->get_timemodified(); 625 $file['sortorder'] = $fileinfo->get_sortorder(); 626 $file['userid'] = $fileinfo->get_userid(); 627 $file['author'] = $fileinfo->get_author(); 628 $file['license'] = $fileinfo->get_license(); 629 $file['mimetype'] = $fileinfo->get_mimetype(); 630 $file['isexternalfile'] = $fileinfo->is_external_file(); 631 if ($file['isexternalfile']) { 632 $file['repositorytype'] = $fileinfo->get_repository_type(); 633 } 634 $contents[] = $file; 635 } 636 } 637 638 // First content is the structure in encoded JSON format. 639 $structurefile = array(); 640 $structurefile['type'] = 'content'; 641 $structurefile['filename'] = 'structure'; 642 $structurefile['filepath'] = "/"; 643 $structurefile['filesize'] = 0; 644 $structurefile['fileurl'] = null; 645 $structurefile['timecreated'] = $book->timecreated; 646 $structurefile['timemodified'] = $book->timemodified; 647 $structurefile['content'] = json_encode(array_values($structure)); 648 $structurefile['sortorder'] = 0; 649 $structurefile['userid'] = null; 650 $structurefile['author'] = null; 651 $structurefile['license'] = null; 652 653 // Add it as first element. 654 array_unshift($contents, $structurefile); 655 656 return $contents; 657 } 658 659 /** 660 * Mark the activity completed (if required) and trigger the course_module_viewed event. 661 * 662 * @param stdClass $book book object 663 * @param stdClass $chapter chapter object 664 * @param bool $islaschapter is the las chapter of the book? 665 * @param stdClass $course course object 666 * @param stdClass $cm course module object 667 * @param stdClass $context context object 668 * @since Moodle 3.0 669 */ 670 function book_view($book, $chapter, $islastchapter, $course, $cm, $context) { 671 672 // First case, we are just opening the book. 673 if (empty($chapter)) { 674 \mod_book\event\course_module_viewed::create_from_book($book, $context)->trigger(); 675 676 } else { 677 \mod_book\event\chapter_viewed::create_from_chapter($book, $context, $chapter)->trigger(); 678 679 if ($islastchapter) { 680 // We cheat a bit here in assuming that viewing the last page means the user viewed the whole book. 681 $completion = new completion_info($course); 682 $completion->set_module_viewed($cm); 683 } 684 } 685 } 686 687 /** 688 * Check if the module has any update that affects the current user since a given time. 689 * 690 * @param cm_info $cm course module data 691 * @param int $from the time to check updates from 692 * @param array $filter if we need to check only specific updates 693 * @return stdClass an object with the different type of areas indicating if they were updated or not 694 * @since Moodle 3.2 695 */ 696 function book_check_updates_since(cm_info $cm, $from, $filter = array()) { 697 global $DB; 698 699 $context = $cm->context; 700 $updates = new stdClass(); 701 if (!has_capability('mod/book:read', $context)) { 702 return $updates; 703 } 704 $updates = course_check_module_updates_since($cm, $from, array('content'), $filter); 705 706 $select = 'bookid = :id AND (timecreated > :since1 OR timemodified > :since2)'; 707 $params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from); 708 if (!has_capability('mod/book:viewhiddenchapters', $context)) { 709 $select .= ' AND hidden = 0'; 710 } 711 $updates->entries = (object) array('updated' => false); 712 $entries = $DB->get_records_select('book_chapters', $select, $params, '', 'id'); 713 if (!empty($entries)) { 714 $updates->entries->updated = true; 715 $updates->entries->itemids = array_keys($entries); 716 } 717 718 return $updates; 719 } 720 721 /** 722 * Get icon mapping for font-awesome. 723 */ 724 function mod_book_get_fontawesome_icon_map() { 725 return [ 726 'mod_book:chapter' => 'fa-bookmark-o', 727 'mod_book:nav_prev' => 'fa-arrow-left', 728 'mod_book:nav_sep' => 'fa-minus', 729 'mod_book:add' => 'fa-plus', 730 'mod_book:nav_next' => 'fa-arrow-right', 731 'mod_book:nav_exit' => 'fa-arrow-up', 732 ]; 733 } 734 735 /** 736 * This function receives a calendar event and returns the action associated with it, or null if there is none. 737 * 738 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event 739 * is not displayed on the block. 740 * 741 * @param calendar_event $event 742 * @param \core_calendar\action_factory $factory 743 * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default). 744 * @return \core_calendar\local\event\entities\action_interface|null 745 */ 746 function mod_book_core_calendar_provide_event_action(calendar_event $event, 747 \core_calendar\action_factory $factory, 748 int $userid = 0) { 749 global $USER; 750 751 if (empty($userid)) { 752 $userid = $USER->id; 753 } 754 755 $cm = get_fast_modinfo($event->courseid, $userid)->instances['book'][$event->instance]; 756 757 if (!$cm->uservisible) { 758 // The module is not visible to the user for any reason. 759 return null; 760 } 761 762 $context = context_module::instance($cm->id); 763 764 if (!has_capability('mod/book:read', $context, $userid)) { 765 return null; 766 } 767 768 $completion = new \completion_info($cm->get_course()); 769 770 $completiondata = $completion->get_data($cm, false, $userid); 771 772 if ($completiondata->completionstate != COMPLETION_INCOMPLETE) { 773 return null; 774 } 775 776 return $factory->create_instance( 777 get_string('view'), 778 new \moodle_url('/mod/book/view.php', ['id' => $cm->id]), 779 1, 780 true 781 ); 782 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body