Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 * This file contains the parent class for moodle blocks, block_base. 19 * 20 * @package core_block 21 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 22 */ 23 24 /// Constants 25 26 /** 27 * Block type of list. Contents of block should be set as an associative array in the content object as items ($this->content->items). Optionally include footer text in $this->content->footer. 28 */ 29 define('BLOCK_TYPE_LIST', 1); 30 31 /** 32 * Block type of text. Contents of block should be set to standard html text in the content object as items ($this->content->text). Optionally include footer text in $this->content->footer. 33 */ 34 define('BLOCK_TYPE_TEXT', 2); 35 /** 36 * Block type of tree. $this->content->items is a list of tree_item objects and $this->content->footer is a string. 37 */ 38 define('BLOCK_TYPE_TREE', 3); 39 40 /** 41 * Class for describing a moodle block, all Moodle blocks derive from this class 42 * 43 * @author Jon Papaioannou 44 * @package core_block 45 */ 46 class block_base { 47 48 /** 49 * Internal var for storing/caching translated strings 50 * @var string $str 51 */ 52 var $str; 53 54 /** 55 * The title of the block to be displayed in the block title area. 56 * @var string $title 57 */ 58 var $title = NULL; 59 60 /** 61 * The name of the block to be displayed in the block title area if the title is empty. 62 * @var string arialabel 63 */ 64 var $arialabel = NULL; 65 66 /** 67 * The type of content that this block creates. Currently support options - BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT 68 * @var int $content_type 69 */ 70 var $content_type = BLOCK_TYPE_TEXT; 71 72 /** 73 * An object to contain the information to be displayed in the block. 74 * @var stdClass $content 75 */ 76 var $content = NULL; 77 78 /** 79 * The initialized instance of this block object. 80 * @var stdClass $instance 81 */ 82 var $instance = NULL; 83 84 /** 85 * The page that this block is appearing on. 86 * @var moodle_page 87 */ 88 public $page = NULL; 89 90 /** 91 * This blocks's context. 92 * @var context 93 */ 94 public $context = NULL; 95 96 /** 97 * An object containing the instance configuration information for the current instance of this block. 98 * @var stdClass $config 99 */ 100 var $config = NULL; 101 102 /** 103 * How often the cronjob should run, 0 if not at all. 104 * @var int $cron 105 */ 106 107 var $cron = NULL; 108 109 /// Class Functions 110 111 /** 112 * Fake constructor to keep PHP5 happy 113 * 114 */ 115 function __construct() { 116 $this->init(); 117 } 118 119 /** 120 * Function that can be overridden to do extra cleanup before 121 * the database tables are deleted. (Called once per block, not per instance!) 122 */ 123 function before_delete() { 124 } 125 126 /** 127 * Returns the block name, as present in the class name, 128 * the database, the block directory, etc etc. 129 * 130 * @return string 131 */ 132 function name() { 133 // Returns the block name, as present in the class name, 134 // the database, the block directory, etc etc. 135 $myname = strtolower(get_class($this)); 136 return substr($myname, strpos($myname, '_') + 1); 137 } 138 139 /** 140 * Parent class version of this function simply returns NULL 141 * This should be implemented by the derived class to return 142 * the content object. 143 * 144 * @return stdObject 145 */ 146 function get_content() { 147 // This should be implemented by the derived class. 148 return NULL; 149 } 150 151 /** 152 * Returns the class $title var value. 153 * 154 * Intentionally doesn't check if a title is set. 155 * This is already done in {@link _self_test()} 156 * 157 * @return string $this->title 158 */ 159 function get_title() { 160 // Intentionally doesn't check if a title is set. This is already done in _self_test() 161 return $this->title; 162 } 163 164 /** 165 * Returns the class $content_type var value. 166 * 167 * Intentionally doesn't check if content_type is set. 168 * This is already done in {@link _self_test()} 169 * 170 * @return string $this->content_type 171 */ 172 function get_content_type() { 173 // Intentionally doesn't check if a content_type is set. This is already done in _self_test() 174 return $this->content_type; 175 } 176 177 /** 178 * Returns true or false, depending on whether this block has any content to display 179 * and whether the user has permission to view the block 180 * 181 * @return boolean 182 */ 183 function is_empty() { 184 if ( !has_capability('moodle/block:view', $this->context) ) { 185 return true; 186 } 187 188 $this->get_content(); 189 return(empty($this->content->text) && empty($this->content->footer)); 190 } 191 192 /** 193 * First sets the current value of $this->content to NULL 194 * then calls the block's {@link get_content()} function 195 * to set its value back. 196 * 197 * @return stdObject 198 */ 199 function refresh_content() { 200 // Nothing special here, depends on content() 201 $this->content = NULL; 202 return $this->get_content(); 203 } 204 205 /** 206 * Return a block_contents object representing the full contents of this block. 207 * 208 * This internally calls ->get_content(), and then adds the editing controls etc. 209 * 210 * You probably should not override this method, but instead override 211 * {@link html_attributes()}, {@link formatted_contents()} or {@link get_content()}, 212 * {@link hide_header()}, {@link (get_edit_controls)}, etc. 213 * 214 * @return block_contents a representation of the block, for rendering. 215 * @since Moodle 2.0. 216 */ 217 public function get_content_for_output($output) { 218 global $CFG; 219 220 // We can exit early if the current user doesn't have the capability to view the block. 221 if (!has_capability('moodle/block:view', $this->context)) { 222 return null; 223 } 224 225 $bc = new block_contents($this->html_attributes()); 226 $bc->attributes['data-block'] = $this->name(); 227 $bc->blockinstanceid = $this->instance->id; 228 $bc->blockpositionid = $this->instance->blockpositionid; 229 230 if ($this->instance->visible) { 231 $bc->content = $this->formatted_contents($output); 232 if (!empty($this->content->footer)) { 233 $bc->footer = $this->content->footer; 234 } 235 } else { 236 $bc->add_class('invisibleblock'); 237 } 238 239 if (!$this->hide_header()) { 240 $bc->title = $this->title; 241 } 242 243 if (empty($bc->title)) { 244 $bc->arialabel = new lang_string('pluginname', get_class($this)); 245 $this->arialabel = $bc->arialabel; 246 } 247 248 if ($this->page->user_is_editing() && $this->instance_can_be_edited()) { 249 $bc->controls = $this->page->blocks->edit_controls($this); 250 } else { 251 // we must not use is_empty on hidden blocks 252 if ($this->is_empty() && !$bc->controls) { 253 return null; 254 } 255 } 256 257 if (empty($CFG->allowuserblockhiding) 258 || (empty($bc->content) && empty($bc->footer)) 259 || !$this->instance_can_be_collapsed()) { 260 $bc->collapsible = block_contents::NOT_HIDEABLE; 261 } else if (get_user_preferences('block' . $bc->blockinstanceid . 'hidden', false)) { 262 $bc->collapsible = block_contents::HIDDEN; 263 } else { 264 $bc->collapsible = block_contents::VISIBLE; 265 } 266 267 if ($this->instance_can_be_docked() && !$this->hide_header()) { 268 $bc->dockable = true; 269 } 270 271 $bc->annotation = ''; // TODO MDL-19398 need to work out what to say here. 272 273 return $bc; 274 } 275 276 277 /** 278 * Return an object containing all the block content to be returned by external functions. 279 * 280 * If your block is returning formatted content or provide files for download, you should override this method to use the 281 * \core_external\util::format_text, \core_external\util::format_string functions for formatting or external_util::get_area_files for files. 282 * 283 * @param core_renderer $output the rendered used for output 284 * @return stdClass object containing the block title, central content, footer and linked files (if any). 285 * @since Moodle 3.6 286 */ 287 public function get_content_for_external($output) { 288 $bc = new stdClass; 289 $bc->title = null; 290 $bc->content = null; 291 $bc->contentformat = FORMAT_HTML; 292 $bc->footer = null; 293 $bc->files = []; 294 295 if ($this->instance->visible) { 296 $bc->content = $this->formatted_contents($output); 297 if (!empty($this->content->footer)) { 298 $bc->footer = $this->content->footer; 299 } 300 } 301 302 if (!$this->hide_header()) { 303 $bc->title = $this->title; 304 } 305 306 return $bc; 307 } 308 309 /** 310 * Return the plugin config settings for external functions. 311 * 312 * In some cases the configs will need formatting or be returned only if the current user has some capabilities enabled. 313 * 314 * @return stdClass the configs for both the block instance and plugin (as object with name -> value) 315 * @since Moodle 3.8 316 */ 317 public function get_config_for_external() { 318 return (object) [ 319 'instance' => new stdClass(), 320 'plugin' => new stdClass(), 321 ]; 322 } 323 324 /** 325 * Convert the contents of the block to HTML. 326 * 327 * This is used by block base classes like block_list to convert the structured 328 * $this->content->list and $this->content->icons arrays to HTML. So, in most 329 * blocks, you probaby want to override the {@link get_contents()} method, 330 * which generates that structured representation of the contents. 331 * 332 * @param $output The core_renderer to use when generating the output. 333 * @return string the HTML that should appearn in the body of the block. 334 * @since Moodle 2.0. 335 */ 336 protected function formatted_contents($output) { 337 $this->get_content(); 338 $this->get_required_javascript(); 339 if (!empty($this->content->text)) { 340 return $this->content->text; 341 } else { 342 return ''; 343 } 344 } 345 346 /** 347 * Tests if this block has been implemented correctly. 348 * Also, $errors isn't used right now 349 * 350 * @return boolean 351 */ 352 353 function _self_test() { 354 // Tests if this block has been implemented correctly. 355 // Also, $errors isn't used right now 356 $errors = array(); 357 358 $correct = true; 359 if ($this->get_title() === NULL) { 360 $errors[] = 'title_not_set'; 361 $correct = false; 362 } 363 if (!in_array($this->get_content_type(), array(BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT, BLOCK_TYPE_TREE))) { 364 $errors[] = 'invalid_content_type'; 365 $correct = false; 366 } 367 //following selftest was not working when roles&capabilities were used from block 368 /* if ($this->get_content() === NULL) { 369 $errors[] = 'content_not_set'; 370 $correct = false; 371 }*/ 372 $formats = $this->applicable_formats(); 373 if (empty($formats) || array_sum($formats) === 0) { 374 $errors[] = 'no_formats'; 375 $correct = false; 376 } 377 378 return $correct; 379 } 380 381 /** 382 * Subclasses should override this and return true if the 383 * subclass block has a settings.php file. 384 * 385 * @return boolean 386 */ 387 function has_config() { 388 return false; 389 } 390 391 /** 392 * Default behavior: save all variables as $CFG properties 393 * You don't need to override this if you 're satisfied with the above 394 * 395 * @deprecated since Moodle 2.9 MDL-49385 - Please use Admin Settings functionality to save block configuration. 396 */ 397 function config_save($data) { 398 throw new coding_exception('config_save() can not be used any more, use Admin Settings functionality to save block configuration.'); 399 } 400 401 /** 402 * Which page types this block may appear on. 403 * 404 * The information returned here is processed by the 405 * {@link blocks_name_allowed_in_format()} function. Look there if you need 406 * to know exactly how this works. 407 * 408 * Default case: everything except mod and tag. 409 * 410 * @return array page-type prefix => true/false. 411 */ 412 function applicable_formats() { 413 // Default case: the block can be used in courses and site index, but not in activities 414 return array('all' => true, 'mod' => false, 'tag' => false); 415 } 416 417 418 /** 419 * Default return is false - header will be shown 420 * @return boolean 421 */ 422 function hide_header() { 423 return false; 424 } 425 426 /** 427 * Return any HTML attributes that you want added to the outer <div> that 428 * of the block when it is output. 429 * 430 * Because of the way certain JS events are wired it is a good idea to ensure 431 * that the default values here still get set. 432 * I found the easiest way to do this and still set anything you want is to 433 * override it within your block in the following way 434 * 435 * <code php> 436 * function html_attributes() { 437 * $attributes = parent::html_attributes(); 438 * $attributes['class'] .= ' mynewclass'; 439 * return $attributes; 440 * } 441 * </code> 442 * 443 * @return array attribute name => value. 444 */ 445 function html_attributes() { 446 $attributes = array( 447 'id' => 'inst' . $this->instance->id, 448 'class' => 'block_' . $this->name() . ' block', 449 'role' => $this->get_aria_role() 450 ); 451 if ($this->hide_header()) { 452 $attributes['class'] .= ' no-header'; 453 } 454 if ($this->instance_can_be_docked() && get_user_preferences('docked_block_instance_' . $this->instance->id, 0)) { 455 $attributes['class'] .= ' dock_on_load'; 456 } 457 return $attributes; 458 } 459 460 /** 461 * Set up a particular instance of this class given data from the block_insances 462 * table and the current page. (See {@link block_manager::load_blocks()}.) 463 * 464 * @param stdClass $instance data from block_insances, block_positions, etc. 465 * @param moodle_page $page the page this block is on. 466 */ 467 function _load_instance($instance, $page) { 468 if (!empty($instance->configdata)) { 469 $this->config = unserialize_object(base64_decode($instance->configdata)); 470 } 471 $this->instance = $instance; 472 $this->context = context_block::instance($instance->id); 473 $this->page = $page; 474 $this->specialization(); 475 } 476 477 /** 478 * Allows the block to load any JS it requires into the page. 479 * 480 * By default this function simply permits the user to dock the block if it is dockable. 481 * 482 * Left null as of MDL-64506. 483 */ 484 function get_required_javascript() { 485 } 486 487 /** 488 * This function is called on your subclass right after an instance is loaded 489 * Use this function to act on instance data just after it's loaded and before anything else is done 490 * For instance: if your block will have different title's depending on location (site, course, blog, etc) 491 */ 492 function specialization() { 493 // Just to make sure that this method exists. 494 } 495 496 /** 497 * Is each block of this type going to have instance-specific configuration? 498 * Normally, this setting is controlled by {@link instance_allow_multiple()}: if multiple 499 * instances are allowed, then each will surely need its own configuration. However, in some 500 * cases it may be necessary to provide instance configuration to blocks that do not want to 501 * allow multiple instances. In that case, make this function return true. 502 * I stress again that this makes a difference ONLY if {@link instance_allow_multiple()} returns false. 503 * @return boolean 504 */ 505 function instance_allow_config() { 506 return false; 507 } 508 509 /** 510 * Are you going to allow multiple instances of each block? 511 * If yes, then it is assumed that the block WILL USE per-instance configuration 512 * @return boolean 513 */ 514 function instance_allow_multiple() { 515 // Are you going to allow multiple instances of each block? 516 // If yes, then it is assumed that the block WILL USE per-instance configuration 517 return false; 518 } 519 520 /** 521 * Serialize and store config data 522 */ 523 function instance_config_save($data, $nolongerused = false) { 524 global $DB; 525 $DB->update_record('block_instances', ['id' => $this->instance->id, 526 'configdata' => base64_encode(serialize($data)), 'timemodified' => time()]); 527 } 528 529 /** 530 * Replace the instance's configuration data with those currently in $this->config; 531 */ 532 function instance_config_commit($nolongerused = false) { 533 global $DB; 534 $this->instance_config_save($this->config); 535 } 536 537 /** 538 * Do any additional initialization you may need at the time a new block instance is created 539 * @return boolean 540 */ 541 function instance_create() { 542 return true; 543 } 544 545 /** 546 * Copy any block-specific data when copying to a new block instance. 547 * @param int $fromid the id number of the block instance to copy from 548 * @return boolean 549 */ 550 public function instance_copy($fromid) { 551 return true; 552 } 553 554 /** 555 * Delete everything related to this instance if you have been using persistent storage other than the configdata field. 556 * @return boolean 557 */ 558 function instance_delete() { 559 return true; 560 } 561 562 /** 563 * Allows the block class to have a say in the user's ability to edit (i.e., configure) blocks of this type. 564 * The framework has first say in whether this will be allowed (e.g., no editing allowed unless in edit mode) 565 * but if the framework does allow it, the block can still decide to refuse. 566 * @return boolean 567 */ 568 function user_can_edit() { 569 global $USER; 570 571 if (has_capability('moodle/block:edit', $this->context)) { 572 return true; 573 } 574 575 // The blocks in My Moodle are a special case. We want them to inherit from the user context. 576 if (!empty($USER->id) 577 && $this->instance->parentcontextid == $this->page->context->id // Block belongs to this page 578 && $this->page->context->contextlevel == CONTEXT_USER // Page belongs to a user 579 && $this->page->context->instanceid == $USER->id) { // Page belongs to this user 580 return has_capability('moodle/my:manageblocks', $this->page->context); 581 } 582 583 return false; 584 } 585 586 /** 587 * Allows the block class to have a say in the user's ability to create new instances of this block. 588 * The framework has first say in whether this will be allowed (e.g., no adding allowed unless in edit mode) 589 * but if the framework does allow it, the block can still decide to refuse. 590 * This function has access to the complete page object, the creation related to which is being determined. 591 * 592 * @param moodle_page $page 593 * @return boolean 594 */ 595 function user_can_addto($page) { 596 global $CFG; 597 require_once($CFG->dirroot . '/user/lib.php'); 598 599 // List of formats this block supports. 600 $formats = $this->applicable_formats(); 601 602 // Check if user is trying to add blocks to their profile page. 603 $userpagetypes = user_page_type_list($page->pagetype, null, null); 604 if (array_key_exists($page->pagetype, $userpagetypes)) { 605 $capability = 'block/' . $this->name() . ':addinstance'; 606 return $this->has_add_block_capability($page, $capability) 607 && has_capability('moodle/user:manageownblocks', $page->context); 608 } 609 610 // The blocks in My Moodle are a special case and use a different capability. 611 $mypagetypes = my_page_type_list($page->pagetype); // Get list of possible my page types. 612 613 if (array_key_exists($page->pagetype, $mypagetypes)) { // Ensure we are on a page with a my page type. 614 // If the block cannot be displayed on /my it is ok if the myaddinstance capability is not defined. 615 // Is 'my' explicitly forbidden? 616 // If 'all' has not been allowed, has 'my' been explicitly allowed? 617 if ((isset($formats['my']) && $formats['my'] == false) 618 || (empty($formats['all']) && empty($formats['my']))) { 619 620 // Block cannot be added to /my regardless of capabilities. 621 return false; 622 } else { 623 $capability = 'block/' . $this->name() . ':myaddinstance'; 624 return $this->has_add_block_capability($page, $capability) 625 && has_capability('moodle/my:manageblocks', $page->context); 626 } 627 } 628 // Check if this is a block only used on /my. 629 unset($formats['my']); 630 if (empty($formats)) { 631 // Block can only be added to /my - return false. 632 return false; 633 } 634 635 $capability = 'block/' . $this->name() . ':addinstance'; 636 if ($this->has_add_block_capability($page, $capability) 637 && has_capability('moodle/block:edit', $page->context)) { 638 return true; 639 } 640 641 return false; 642 } 643 644 /** 645 * Returns true if the user can add a block to a page. 646 * 647 * @param moodle_page $page 648 * @param string $capability the capability to check 649 * @return boolean true if user can add a block, false otherwise. 650 */ 651 private function has_add_block_capability($page, $capability) { 652 // Check if the capability exists. 653 if (!get_capability_info($capability)) { 654 // Debug warning that the capability does not exist, but no more than once per page. 655 static $warned = array(); 656 if (!isset($warned[$this->name()])) { 657 debugging('The block ' .$this->name() . ' does not define the standard capability ' . 658 $capability , DEBUG_DEVELOPER); 659 $warned[$this->name()] = 1; 660 } 661 // If the capability does not exist, the block can always be added. 662 return true; 663 } else { 664 return has_capability($capability, $page->context); 665 } 666 } 667 668 static function get_extra_capabilities() { 669 return array('moodle/block:view', 'moodle/block:edit'); 670 } 671 672 /** 673 * Can be overridden by the block to prevent the block from being dockable. 674 * 675 * @return bool 676 * 677 * Return false as per MDL-64506 678 */ 679 public function instance_can_be_docked() { 680 return false; 681 } 682 683 /** 684 * If overridden and set to false by the block it will not be hidable when 685 * editing is turned on. 686 * 687 * @return bool 688 */ 689 public function instance_can_be_hidden() { 690 return true; 691 } 692 693 /** 694 * If overridden and set to false by the block it will not be collapsible. 695 * 696 * @return bool 697 */ 698 public function instance_can_be_collapsed() { 699 return true; 700 } 701 702 /** 703 * If overridden and set to false by the block it will not be editable. 704 * 705 * @return bool 706 */ 707 public function instance_can_be_edited() { 708 return true; 709 } 710 711 /** @callback callback functions for comments api */ 712 public static function comment_template($options) { 713 $ret = <<<EOD 714 <div class="comment-userpicture">___picture___</div> 715 <div class="comment-content"> 716 ___name___ - <span>___time___</span> 717 <div>___content___</div> 718 </div> 719 EOD; 720 return $ret; 721 } 722 public static function comment_permissions($options) { 723 return array('view'=>true, 'post'=>true); 724 } 725 public static function comment_url($options) { 726 return null; 727 } 728 public static function comment_display($comments, $options) { 729 return $comments; 730 } 731 public static function comment_add(&$comments, $options) { 732 return true; 733 } 734 735 /** 736 * Returns the aria role attribute that best describes this block. 737 * 738 * Region is the default, but this should be overridden by a block is there is a region child, or even better 739 * a landmark child. 740 * 741 * Options are as follows: 742 * - landmark 743 * - application 744 * - banner 745 * - complementary 746 * - contentinfo 747 * - form 748 * - main 749 * - navigation 750 * - search 751 * 752 * @return string 753 */ 754 public function get_aria_role() { 755 return 'complementary'; 756 } 757 758 /** 759 * This method can be overriden to add some extra checks to decide whether the block can be added or not to a page. 760 * It doesn't need to do the standard capability checks as they will be performed by has_add_block_capability(). 761 * This method is user agnostic. If you want to check if a user can add a block or not, you should use user_can_addto(). 762 * 763 * @param moodle_page $page The page where this block will be added. 764 * @return bool Whether the block can be added or not to the given page. 765 */ 766 public function can_block_be_added(moodle_page $page): bool { 767 return true; 768 } 769 } 770 771 /** 772 * Specialized class for displaying a block with a list of icons/text labels 773 * 774 * The get_content method should set $this->content->items and (optionally) 775 * $this->content->icons, instead of $this->content->text. 776 * 777 * @author Jon Papaioannou 778 * @package core_block 779 */ 780 781 class block_list extends block_base { 782 var $content_type = BLOCK_TYPE_LIST; 783 784 function is_empty() { 785 if ( !has_capability('moodle/block:view', $this->context) ) { 786 return true; 787 } 788 789 $this->get_content(); 790 return (empty($this->content->items) && empty($this->content->footer)); 791 } 792 793 protected function formatted_contents($output) { 794 $this->get_content(); 795 $this->get_required_javascript(); 796 if (!empty($this->content->items)) { 797 return $output->list_block_contents($this->content->icons, $this->content->items); 798 } else { 799 return ''; 800 } 801 } 802 803 function html_attributes() { 804 $attributes = parent::html_attributes(); 805 $attributes['class'] .= ' list_block'; 806 return $attributes; 807 } 808 809 } 810 811 /** 812 * Specialized class for displaying a tree menu. 813 * 814 * The {@link get_content()} method involves setting the content of 815 * <code>$this->content->items</code> with an array of {@link tree_item} 816 * objects (these are the top-level nodes). The {@link tree_item::children} 817 * property may contain more tree_item objects, and so on. The tree_item class 818 * itself is abstract and not intended for use, use one of it's subclasses. 819 * 820 * Unlike {@link block_list}, the icons are specified as part of the items, 821 * not in a separate array. 822 * 823 * @author Alan Trick 824 * @package core_block 825 * @internal this extends block_list so we get is_empty() for free 826 */ 827 class block_tree extends block_list { 828 829 /** 830 * @var int specifies the manner in which contents should be added to this 831 * block type. In this case <code>$this->content->items</code> is used with 832 * {@link tree_item}s. 833 */ 834 public $content_type = BLOCK_TYPE_TREE; 835 836 /** 837 * Make the formatted HTML ouput. 838 * 839 * Also adds the required javascript call to the page output. 840 * 841 * @param core_renderer $output 842 * @return string HTML 843 */ 844 protected function formatted_contents($output) { 845 // based of code in admin_tree 846 global $PAGE; // TODO change this when there is a proper way for blocks to get stuff into head. 847 static $eventattached; 848 if ($eventattached===null) { 849 $eventattached = true; 850 } 851 if (!$this->content) { 852 $this->content = new stdClass; 853 $this->content->items = array(); 854 } 855 $this->get_required_javascript(); 856 $this->get_content(); 857 $content = $output->tree_block_contents($this->content->items,array('class'=>'block_tree list')); 858 return $content; 859 } 860 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body