. /** * Block Class and Functions * * @todo Document what this file does * * @package moodlecore * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Block Defines */ define('BLOCK_MOVE_LEFT', 0x01); define('BLOCK_MOVE_RIGHT', 0x02); define('BLOCK_MOVE_UP', 0x04); define('BLOCK_MOVE_DOWN', 0x08); define('BLOCK_CONFIGURE', 0x10); define('BLOCK_POS_LEFT', 'side-pre'); define('BLOCK_POS_RIGHT', 'side-post'); define('BLOCKS_PINNED_TRUE',0); define('BLOCKS_PINNED_FALSE',1); define('BLOCKS_PINNED_BOTH',2); require_once($CFG->libdir.'/pagelib.php'); /** * * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package moodlecore */ class block_not_on_page_exception extends moodle_exception { /** * Contructor * * @param int $instanceid * @param object $page */ public function __construct($instanceid, $page) { $a = new stdClass; $a->instanceid = $instanceid; $a->url = $page->url; parent::__construct('blockdoesnotexistonpage', '', $page->url, $a); } } /** * Block Manager * * This class keeps track of the block that should appear on a moodle_page. * The page to work with as passed to the constructor. * The only fields of moodle_page that is uses are ->context, ->pagetype and * ->subpage, so instead of passing a full moodle_page object, you may also * pass a stdClass object with those three fields. These field values are read * only at the point that the load_blocks() method is called. It is the caller's * responsibility to ensure that those fields do not subsequently change. * * * Note about the weird 'implements ArrayAccess' part of the declaration: * * ArrayAccess is a magic PHP5 thing. If your class implements the ArrayAccess * interface, then other code can use the $object[$index] syntax, and it will * call the offsetGet method of the object. * See http://php.net/manual/en/class.arrayaccess.php * * So, why do we do this here? Basically, some of the deprecated blocks methods * like blocks_setup used to return an array of blocks on the page, with array * keys BLOCK_POS_LEFT, BLOCK_POS_RIGHT. We can keep legacy code that calls those * deprecated functions mostly working by changing blocks_setup to return the * block_manger object, and then use 'implements ArrayAccess' so that the right * thing happens when legacy code does something like $pageblocks[BLOCK_POS_LEFT]. * * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package moodlecore */ class block_manager implements ArrayAccess { /// Field declarations ========================================================= /** @var object */ protected $page; /** @var array */ protected $regions = array(); /** @var string */ protected $defaultregion; /** @var array */ protected $allblocks = null; // Will be get_records('blocks'); /** @var array */ protected $addableblocks = null; // Will be a subset of $allblocks. /** * Will be an array region-name => array(db rows loaded in load_blocks); * @var array */ protected $birecordsbyregion = null; /** * array region-name => array(block objects); populated as necessary by * the ensure_instances_exist method. * @var array */ protected $blockinstances = array(); /** * array region-name => array(block_content objects) what acutally needs to * be displayed in each region. * @var array */ protected $visibleblockcontent = array(); /// Constructor ================================================================ /** * Constructor. * @param object $page the moodle_page object object we are managing the blocks for, * or a reasonable faxilimily. (See the comment at the top of this classe * and {@link http://en.wikipedia.org/wiki/Duck_typing}) */ public function __construct($page) { $this->page = $page; } /// Getter methods ============================================================= /** * Get an array of all region names on this page where a block may appear * * @return array the internal names of the regions on this page where block may appear. */ public function get_regions() { return array_keys($this->regions); } /** * Get the region name of the region blocks are added to by default * * @return string the internal names of the region where new blocks are added * by default, and where any blocks from an unrecognised region are shown. * (Imagine that blocks were added with one theme selected, then you switched * to a theme with different block positions.) */ public function get_default_region() { return $this->defaultregion; } /** * The list of block types that may be added to this page. * * @return array block id => record from block table. */ public function get_addable_blocks() { $this->check_is_loaded(); if (!is_null($this->addableblocks)) { return $this->addableblocks; } // Lazy load. $this->addableblocks = array(); $allblocks = blocks_get_record(); if (empty($allblocks)) { return $this->addableblocks; } $pageformat = $this->page->pagetype; foreach($allblocks as $block) { if ($block->visible && (block_method_result($block->name, 'instance_allow_multiple') || !$this->is_block_present($block->id)) && blocks_name_allowed_in_format($block->name, $pageformat)) { $this->addableblocks[$block->id] = $block; } } return $this->addableblocks; } /** * Find out if a block is present ? just a guess * @todo Write this function and document */ public function is_block_present($blocktypeid) { // TODO } /** * Find out if a block type is known by the system * * @param string $blockname the name of ta type of block. * @param boolean $includeinvisible if false (default) only check 'visible' blocks, that is, blocks enabled by the admin. * @return boolean true if this block in installed. */ public function is_known_block_type($blockname, $includeinvisible = false) { $blocks = $this->get_installed_blocks(); foreach ($blocks as $block) { if ($block->name == $blockname && ($includeinvisible || $block->visible)) { return true; } } return false; } /** * Find out if a region exists on a page * * @param string $region a region name * @return boolean true if this retion exists on this page. */ public function is_known_region($region) { return array_key_exists($region, $this->regions); } /** * Get an array of all blocks within a given region * * @param string $region a block region that exists on this page. * @return array of block instances. */ public function get_blocks_for_region($region) { $this->check_is_loaded(); $this->ensure_instances_exist($region); return $this->blockinstances[$region]; } /** * Returns an array of block content objects that exist in a region * * @param $region a block region that exists on this page. * @return array of block block_content objects for all the blocks in a region. */ public function get_content_for_region($region) { $this->check_is_loaded(); $this->ensure_content_created($region); return $this->visibleblockcontent[$region]; } /** * Get an array of all of the installed blocks. * * @global object * @return array contents of the block table. */ public function get_installed_blocks() { global $DB; if (is_null($this->allblocks)) { $this->allblocks = $DB->get_records('block'); } return $this->allblocks; } /// Setter methods ============================================================= /** * Add a region to a page * * @param string $region add a named region where blocks may appear on the * current page. This is an internal name, like 'side-pre', not a string to * display in the UI. */ public function add_region($region) { $this->check_not_yet_loaded(); $this->regions[$region] = 1; } /** * Add an array of regions * @see add_region() * * @param array $regions this utility method calls add_region for each array element. */ public function add_regions($regions) { foreach ($regions as $region) { $this->add_region($region); } } /** * Set the default region for new blocks on the page * * @param string $defaultregion the internal names of the region where new * blocks should be added by default, and where any blocks from an * unrecognised region are shown. */ public function set_default_region($defaultregion) { $this->check_not_yet_loaded(); $this->check_region_is_known($defaultregion); $this->defaultregion = $defaultregion; } /// Actions ==================================================================== /** * This method actually loads the blocks for our page from the database. * * @global object * @global object * @uses SQL_PARAMS_NAMED * @param bool|null $includeinvisible * @return void */ public function load_blocks($includeinvisible = NULL) { global $DB, $CFG; if (!is_null($this->birecordsbyregion)) { // Already done. return; } if ($CFG->version < 2009050619) { // Upgrade/install not complete. Don't try too show any blocks. $this->birecordsbyregion = array(); return; } if (is_null($includeinvisible)) { $includeinvisible = $this->page->user_is_editing(); } if ($includeinvisible) { $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; } else { $visiblecheck = ''; } $context = $this->page->context; $contexttest = 'bi.contextid = :contextid2'; $parentcontextparams = array(); $parentcontextids = get_parent_contexts($context); if ($parentcontextids) { list($parentcontexttest, $parentcontextparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000'); $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.contextid $parentcontexttest))"; } $pagetypepatterns = $this->matching_page_type_patterns($this->page->pagetype); list($pagetypepatterntest, $pagetypepatternparams) = $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000'); $params = array( 'subpage1' => $this->page->subpage, 'subpage2' => $this->page->subpage, 'contextid1' => $context->id, 'contextid2' => $context->id, 'pagetype' => $this->page->pagetype, ); $sql = "SELECT bi.id, bi.blockname, bi.contextid, bi.showinsubcontexts, bi.pagetypepattern, bi.subpagepattern, COALESCE(bp.visible, 1) AS visible, COALESCE(bp.region, bi.defaultregion) AS region, COALESCE(bp.weight, bi.defaultweight) AS weight, bi.configdata FROM {block_instances} bi JOIN {block} b ON bi.blockname = b.name LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id AND bp.contextid = :contextid1 AND bp.pagetype = :pagetype AND bp.subpage = :subpage1 WHERE $contexttest AND bi.pagetypepattern $pagetypepatterntest AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2) $visiblecheck AND b.visible = 1 ORDER BY COALESCE(bp.region, bi.defaultregion), COALESCE(bp.weight, bi.defaultweight), bi.id"; $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); $this->birecordsbyregion = $this->prepare_per_region_arrays(); $unknown = array(); foreach ($blockinstances as $bi) { if ($this->is_known_region($bi->region)) { $this->birecordsbyregion[$bi->region][] = $bi; } else { $unknown[] = $bi; } } $this->birecordsbyregion[$this->defaultregion] = array_merge($this->birecordsbyregion[$this->defaultregion], $unknown); } /** * Add a block to the current page, or related pages. The block is added to * context $this->page->contextid. If $pagetypepattern $subpagepattern * * @global object * @uses CONTEXT_COURSE * @uses CONTEXT_BLOCK * @param string $blockname The type of block to add. * @param string $region the block region on this page to add the block to. * @param integer $weight determines the order where this block appears in the region. * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context. * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type. * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage. */ public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) { global $DB; $this->check_known_block_type($blockname); $this->check_region_is_known($region); if (empty($pagetypepattern)) { $pagetypepattern = $this->page->pagetype; } $blockinstance = new stdClass; $blockinstance->blockname = $blockname; $blockinstance->contextid = $this->page->context->id; $blockinstance->showinsubcontexts = !empty($showinsubcontexts); $blockinstance->pagetypepattern = $pagetypepattern; $blockinstance->subpagepattern = $subpagepattern; $blockinstance->defaultregion = $region; $blockinstance->defaultweight = $weight; $blockinstance->configdata = ''; $blockinstance->id = $DB->insert_record('block_instances', $blockinstance); if ($this->page->context->contextlevel == CONTEXT_COURSE) { get_context_instance(CONTEXT_BLOCK, $blockinstance->id); } // If the new instance was created, allow it to do additional setup if($block = block_instance($blockname, $blockinstance)) { $block->instance_create(); } } /** * Convenience method, calls add_block repeatedly for all the blocks in $blocks. * * @param array $blocks array with arrray keys the region names, and values an array of block names. * @param string $pagetypepattern optional. Passed to @see add_block() * @param string $subpagepattern optional. Passed to @see add_block() */ public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL) { $this->add_regions(array_keys($blocks)); foreach ($blocks as $region => $regionblocks) { $weight = 0; foreach ($regionblocks as $blockname) { $this->add_block($blockname, $region, $weight, false, $pagetypepattern, $subpagepattern); $weight += 1; } } } /** * Find a given block by its instance id * * @param integer $instanceid * @return object */ public function find_instance($instanceid) { foreach ($this->regions as $region => $notused) { $this->ensure_instances_exist($region); foreach($this->blockinstances[$region] as $instance) { if ($instance->instance->id == $instanceid) { return $instance; } } } throw new block_not_on_page_exception($instanceid, $this->page); } /// Inner workings ============================================================= /** * Given a specific page type, return all the page type patterns that might * match it. * * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'. * @return array an array of all the page type patterns that might match this page type. */ protected function matching_page_type_patterns($pagetype) { $patterns = array($pagetype, '*'); $bits = explode('-', $pagetype); if (count($bits) == 3 && $bits[0] == 'mod') { if ($bits[2] == 'view') { $patterns[] = 'mod-*-view'; } else if ($bits[2] == 'index') { $patterns[] = 'mod-*-index'; } } while (count($bits) > 0) { $patterns[] = implode('-', $bits) . '-*'; array_pop($bits); } return $patterns; } /** * Check whether the page blocks have been loaded yet * * @return void Throws coding exception if already loaded */ protected function check_not_yet_loaded() { if (!is_null($this->birecordsbyregion)) { throw new coding_exception('block_manager has already loaded the blocks, to it is too late to change things that might affect which blocks are visible.'); } } /** * Check whether the page blocks have been loaded yet * * Nearly identical to the above function {@link check_not_yet_loaded()} except different message * * @return void Throws coding exception if already loaded */ protected function check_is_loaded() { if (is_null($this->birecordsbyregion)) { throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.'); } } /** * Check if a block type is known and usable * * @param string $blockname The block type name to search for * @param bool $includeinvisible Include disabled block types in the intial pass * @return void Coding Exception thrown if unknown or not enabled */ protected function check_known_block_type($blockname, $includeinvisible = false) { if (!$this->is_known_block_type($blockname, $includeinvisible)) { if ($this->is_known_block_type($blockname, true)) { throw new coding_exception('Unknown block type ' . $blockname); } else { throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.'); } } } /** * Check if a region is known by its name * * @param string $region * @return void Coding Exception thrown if the region is not known */ protected function check_region_is_known($region) { if (!$this->is_known_region($region)) { throw new coding_exception('Trying to reference an unknown block region ' . $region); } } /** * Returns an array of region names as keys and nested arrays for values * * @return array an array where the array keys are the region names, and the array * values are empty arrays. */ protected function prepare_per_region_arrays() { $result = array(); foreach ($this->regions as $region => $notused) { $result[$region] = array(); } return $result; } /** * Create a set of new block instance from a record array * * @param array $birecords An array of block instance records * @return array An array of instantiated block_instance objects */ protected function create_block_instances($birecords) { $results = array(); foreach ($birecords as $record) { $results[] = block_instance($record->blockname, $record, $this->page); } return $results; } /** * Return an array of content vars from a set of block instances * * @param array $instances An array of block instances * @return array An array of content vars */ protected function create_block_content($instances) { $results = array(); foreach ($instances as $instance) { if ($instance->is_empty()) { continue; } $content = $instance->get_content(); if (!empty($content)) { $results[] = $content; } } return $results; } /** * Ensure block instances exist for a given region * * @param string $region Check for bi's with the instance with this name */ protected function ensure_instances_exist($region) { $this->check_region_is_known($region); if (!array_key_exists($region, $this->blockinstances)) { $this->blockinstances[$region] = $this->create_block_instances($this->birecordsbyregion[$region]); } } /** * Ensure that there is some content within the given region * * @param string $region The name of the region to check */ protected function ensure_content_created($region) { $this->ensure_instances_exist($region); if (!array_key_exists($region, $this->visibleblockcontent)) { $this->visibleblockcontent[$region] = $this->create_block_content($this->blockinstances[$region]); } } /// Deprecated stuff for backwards compatibility =============================== /** @deprecated Remains to ensure backwards compatibility */ public function offsetSet($offset, $value) { } /** @deprecated Remains to ensure backwards compatibility */ public function offsetExists($offset) { return $this->is_known_region($offset); } /** @deprecated Remains to ensure backwards compatibility */ public function offsetUnset($offset) { } /** @deprecated Remains to ensure backwards compatibility */ public function offsetGet($offset) { return $this->get_blocks_for_region($offset); } } /** * This class holds all the information required to view a block. * * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package moodlecore */ abstract class block_content { /** @var int Id used to uniquely identify this block in the HTML. */ public $id = null; /** @var array Class names to add to this block's container in the HTML. */ public $classes = array(); /** @var string The content that appears in the title bar at the top of the block (HTML). */ public $heading = null; /** @var string Plain text name of this block instance, used in the skip links. */ public $title = null; /** * A (possibly empty) array of editing controls. Array keys should be a * short string, e.g. 'edit', 'move' and the values are the HTML of the icons. * @var array */ public $editingcontrols = array(); /** @var string The content that appears within the block, as HTML. */ public $content = null; /** @var string The content that appears at the end of the block. */ public $footer = null; /** * Any small print that should appear under the block to explain to the * teacher about the block, for example 'This is a sticky block that was * added in the system context.' * @var string */ public $annotation = null; /** @var string The result of the preferred_width method, which the theme may choose to use, or ignore. */ public $preferredwidth = null; public abstract function get_content(); } /// Helper functions for working with block classes ============================ /** * Call a class method (one that does not requrie a block instance) on a block class. * * @param string $blockname the name of the block. * @param string $method the method name. * @param array $param parameters to pass to the method. * @return mixed whatever the method returns. */ function block_method_result($blockname, $method, $param = NULL) { if(!block_load_class($blockname)) { return NULL; } return call_user_func(array('block_'.$blockname, $method), $param); } /** * Creates a new object of the specified block class. * * @param string $blockname the name of the block. * @param $instance block_instances DB table row (optional). * @param moodle_page $page the page this block is appearing on. * @return block_base the requested block instance. */ function block_instance($blockname, $instance = NULL, $page = NULL) { if(!block_load_class($blockname)) { return false; } $classname = 'block_'.$blockname; $retval = new $classname; if($instance !== NULL) { if (is_null($page)) { global $PAGE; $page = $PAGE; } $retval->_load_instance($instance, $page); } return $retval; } /** * Load the block class for a particular type of block. * * @global object * @param string $blockname the name of the block. * @return boolean success or failure. */ function block_load_class($blockname) { global $CFG; if(empty($blockname)) { return false; } $classname = 'block_'.$blockname; if(class_exists($classname)) { return true; } require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); @include_once($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'); // do not throw errors if block code not present return class_exists($classname); } /// Functions that have been deprecated by block_manager ======================= /** * @deprecated since Moodle 2.0 - use $page->blocks->get * * This function returns an array with the IDs of any blocks that you can add to your page. * Parameters are passed by reference for speed; they are not modified at all. * * @param $page the page object. * @param $blockmanager Not used. * @return array of block type ids. */ function blocks_get_missing(&$page, &$blockmanager) { return array_keys($page->blocks->get_addable_blocks()); } /** * Actually delete from the database any blocks that are currently on this page, * but which should not be there according to blocks_name_allowed_in_format. * * @todo Write/Fix this function. Currently returns immediatly * @param $page a page object. */ function blocks_remove_inappropriate($page) { // TODO return; $blockmanager = blocks_get_by_page($page); if(empty($blockmanager)) { return; } if(($pageformat = $page->pagetype) == NULL) { return; } foreach($blockmanager as $region) { foreach($region as $instance) { $block = blocks_get_record($instance->blockid); if(!blocks_name_allowed_in_format($block->name, $pageformat)) { blocks_delete_instance($instance); } } } } /** * Check that a given name is in a permittable format * * @param string $name * @param string $pageformat * @return bool */ function blocks_name_allowed_in_format($name, $pageformat) { $accept = NULL; $maxdepth = -1; $formats = block_method_result($name, 'applicable_formats'); if (!$formats) { $formats = array(); } foreach ($formats as $format => $allowed) { $formatregex = '/^'.str_replace('*', '[^-]*', $format).'.*$/'; $depth = substr_count($format, '-'); if (preg_match($formatregex, $pageformat) && $depth > $maxdepth) { $maxdepth = $depth; $accept = $allowed; } } if ($accept === NULL) { $accept = !empty($formats['all']); } return $accept; } /** * Delete a block, and associated data. * * @global object * @uses CONTEXT_BLOCK * @param object $instance a row from the block_instances table * @param bool $nolongerused legacy parameter. Not used, but kept for bacwards compatibility. * @param bool $skipblockstables for internal use only. Makes @see blocks_delete_all_for_context() more efficient. */ function blocks_delete_instance($instance, $nolongerused = false, $skipblockstables = false) { global $DB; if ($block = block_instance($instance->blockname, $instance)) { $block->instance_delete(); } delete_context(CONTEXT_BLOCK, $instance->id); if (!$skipblockstables) { $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id)); $DB->delete_records('block_instances', array('id' => $instance->id)); } } /** * @deprecated since 2.0 * Delete all the blocks from a particular page. * * @global object * @param string $pagetype the page type. * @param integer $pageid the page id. * @return bool success or failure. */ function blocks_delete_all_on_page($pagetype, $pageid) { global $DB; debugging('Call to deprecated function blocks_delete_all_on_page. ' . 'This function cannot work any more. Doing nothing. ' . 'Please update your code to use another method.', DEBUG_DEVELOPER); return false; } /** * Delete all the blocks that belong to a particular context. * * @global object * @param int $contextid the context id. */ function blocks_delete_all_for_context($contextid) { global $DB; $instances = $DB->get_recordset('block_instances', array('contextid' => $contextid)); foreach ($instances as $instance) { blocks_delete_instance($instance, true); } $instances->close(); $DB->delete_records('block_instances', array('contextid' => $contextid)); $DB->delete_records('block_positions', array('contextid' => $contextid)); } /** * Accepts an array of block instances and checks to see if any of them have content to display * (causing them to calculate their content in the process). Returns true or false. Parameter passed * by reference for speed; the array is actually not modified. * * @todo Deprecate this function * @deprecated * * @param object $blockmanager * @param string $region * @return bool */ function blocks_have_content(&$blockmanager, $region) { // TODO deprecate $content = $blockmanager->get_content_for_region($region); return !empty($content); } /** * This function prints one group of blocks in a page * * @todo Complete this function * * @global object * @global object * @global object * @param object $page * @param object $blockmanager * @param string $region */ function blocks_print_group($page, $blockmanager, $region) { global $COURSE, $CFG, $USER; $isediting = $page->user_is_editing(); $groupblocks = $blockmanager->get_blocks_for_region($region); foreach($groupblocks as $instance) { if (($isediting && empty($instance->pinned))) { $options = 0; // The block can be moved up if it's NOT the first one in its position. If it is, we look at the OR clause: // the first block might still be able to move up if the page says so (i.e., it will change position) // TODO $options |= BLOCK_MOVE_UP * ($instance->weight != 0 || ($page->blocks_move_position($instance, BLOCK_MOVE_UP) != $instance->position)); // Same thing for downward movement // TODO $options |= BLOCK_MOVE_DOWN * ($instance->weight != $maxweight || ($page->blocks_move_position($instance, BLOCK_MOVE_DOWN) != $instance->position)); // For left and right movements, it's up to the page to tell us whether they are allowed // TODO $options |= BLOCK_MOVE_RIGHT * ($page->blocks_move_position($instance, BLOCK_MOVE_RIGHT) != $instance->position); // TODO $options |= BLOCK_MOVE_LEFT * ($page->blocks_move_position($instance, BLOCK_MOVE_LEFT ) != $instance->position); // Finally, the block can be configured if the block class either allows multiple instances, or if it specifically // allows instance configuration (multiple instances override that one). It doesn't have anything to do with what the // administrator has allowed for this block in the site admin options. $options |= BLOCK_CONFIGURE * ( $instance->instance_allow_multiple() || $instance->instance_allow_config() ); $instance->_add_edit_controls($options); } if (false /* TODO */&& !$instance->visible && empty($COURSE->javascriptportal)) { if ($isediting) { $instance->_print_shadow(); } } else { global $COURSE; if(!empty($COURSE->javascriptportal)) { $COURSE->javascriptportal->currentblocksection = $region; } $instance->_print_block(); } if (!empty($COURSE->javascriptportal) && (empty($instance->pinned) || !$instance->pinned)) { $COURSE->javascriptportal->block_add('inst'.$instance->id, !$instance->visible); } } // End foreach if ($page->blocks->get_default_region() == $region && $page->user_is_editing() && $page->user_can_edit_blocks()) { blocks_print_adminblock($page, $blockmanager); } } /** * This iterates over an array of blocks and calculates the preferred width * Parameter passed by reference for speed; it's not modified. * * @todo Finish this function * * @param mixed $instances */ function blocks_preferred_width($instances) { $width = 210; } /** * Get the block record for a particulr blockid. * * @global object * @param $int blockid block type id. If null, an array of all block types is returned. * @param bool $notusedanymore No longer used. * @return array|object row from block table, or all rows. */ function blocks_get_record($blockid = NULL, $notusedanymore = false) { global $PAGE; $blocks = $PAGE->blocks->get_installed_blocks(); if ($blockid === NULL) { return $blocks; } else if (isset($blocks[$blockid])) { return $blocks[$blockid]; } else { return false; } } /** * Find a given block by its blockid within a provide array * * @param int $blockid * @param array $blocksarray * @return bool|object Instance if found else false */ function blocks_find_block($blockid, $blocksarray) { if (empty($blocksarray)) { return false; } foreach($blocksarray as $blockgroup) { if (empty($blockgroup)) { continue; } foreach($blockgroup as $instance) { if($instance->blockid == $blockid) { return $instance; } } } return false; } /** * Simple entry point for anyone that wants to use blocks * * @uses BLOCKS_PINNED_FALSE * @param object $page * @return array */ function blocks_setup(&$page, $pinned = BLOCKS_PINNED_FALSE) { $page->blocks->load_blocks(); blocks_execute_url_action($page, $page->blocks); return $page->blocks; } /** * @todo Document this function, description * * @global object * @global object * @global object * @uses BLOCK_MOVE_UP * @uses BLOCK_MOVE_DOWN * @uses BLOCK_MOVE_RIGHT * @uses BLOCK_MOVE_LEFT * @param object $page The page object * @param object $blockmanager The block manager object * @param string $blockaction One of [config, add, delete] * @param int|object $instanceorid The instance id or a block_instance object * @param bool $pinned * @param bool $redirect To redirect or not to that is the question but you should stick with true */ function blocks_execute_action($page, &$blockmanager, $blockaction, $instanceorid, $pinned=false, $redirect=true) { global $CFG, $USER, $DB; if (!in_array($blockaction, array('config', 'add', 'delete'))) { throw new moodle_exception('Sorry, blocks editing is currently broken. Will be fixed. See MDL-19010.'); } if (is_int($instanceorid)) { $blockid = $instanceorid; } else if (is_object($instanceorid)) { $instance = $instanceorid; } switch($blockaction) { case 'config': // First of all check to see if the block wants to be edited if(!$instance->user_can_edit()) { break; } // Now get the title and AFTER that load up the instance $blocktitle = $instance->get_title(); // Define the data we're going to silently include in the instance config form here, // so we can strip them from the submitted data BEFORE serializing it. $hiddendata = array( 'sesskey' => sesskey(), 'instanceid' => $instance->instance->id, 'blockaction' => 'config' ); // To this data, add anything the page itself needs to display $hiddendata = $page->url->params($hiddendata); if ($data = data_submitted()) { $remove = array_keys($hiddendata); foreach($remove as $item) { unset($data->$item); } $instance->instance_config_save($data); redirect($page->url->out()); } else { // We need to show the config screen, so we highjack the display logic and then die $strheading = get_string('blockconfiga', 'moodle', $blocktitle); $nav = build_navigation($strheading, $page->cm); print_header($strheading, $strheading, $nav); echo '