"MDL-19118, fixed a javascript error on webkit core browsers"
[moodle.git] / lib / blocklib.php
CommitLineData
d4accfc0 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
e8c8cee9 17
18/**
d4accfc0 19 * Block Class and Functions
e8c8cee9 20 *
d4a03c00 21 * This file defines the {@link block_manager} class,
22 *
d4accfc0 23 * @package moodlecore
24 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
e8c8cee9 26 */
0f3fe4b6 27
13a0d3d3 28/**#@+
29 * @deprecated since Moodle 2.0. No longer used.
d4a03c00 30 */
0f3fe4b6 31define('BLOCK_MOVE_LEFT', 0x01);
32define('BLOCK_MOVE_RIGHT', 0x02);
33define('BLOCK_MOVE_UP', 0x04);
34define('BLOCK_MOVE_DOWN', 0x08);
9b4b78fd 35define('BLOCK_CONFIGURE', 0x10);
13a0d3d3 36/**#@-*/
0f3fe4b6 37
13a0d3d3 38/**#@+
39 * Default names for the block regions in the standard theme.
40 */
bb46a4fa 41define('BLOCK_POS_LEFT', 'side-pre');
42define('BLOCK_POS_RIGHT', 'side-post');
13a0d3d3 43/**#@-*/
0e9af917 44
13a0d3d3 45/**#@+
46 * @deprecated since Moodle 2.0. No longer used.
47 */
ee6055eb 48define('BLOCKS_PINNED_TRUE',0);
49define('BLOCKS_PINNED_FALSE',1);
50define('BLOCKS_PINNED_BOTH',2);
13a0d3d3 51/**#@-*/
ee6055eb 52
d4accfc0 53/**
d4a03c00 54 * Exception thrown when someone tried to do something with a block that does
55 * not exist on a page.
d4accfc0 56 *
d4a03c00 57 * @copyright 2009 Tim Hunt
58 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
59 * @since Moodle 2.0
d4accfc0 60 */
f4d38d20 61class block_not_on_page_exception extends moodle_exception {
d4accfc0 62 /**
63 * Contructor
d4a03c00 64 * @param int $instanceid the block instance id of the block that was looked for.
65 * @param object $page the current page.
d4accfc0 66 */
f4d38d20 67 public function __construct($instanceid, $page) {
68 $a = new stdClass;
69 $a->instanceid = $instanceid;
2a3b0763 70 $a->url = $page->url->out();
71 parent::__construct('blockdoesnotexistonpage', '', $page->url->out(), $a);
f4d38d20 72 }
73}
74
86b5ea0f 75/**
76 * This class keeps track of the block that should appear on a moodle_page.
bb46a4fa 77 *
d4a03c00 78 * The page to work with as passed to the constructor.
1d00ec6a 79 *
d4a03c00 80 * @copyright 2009 Tim Hunt
81 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
82 * @since Moodle 2.0
86b5ea0f 83 */
d4a03c00 84class block_manager {
86b5ea0f 85
86/// Field declarations =========================================================
d4a03c00 87
88 /** @var moodle_page the moodle_page we aremanaging blocks for. */
86b5ea0f 89 protected $page;
d4a03c00 90
91 /** @var array region name => 1.*/
86b5ea0f 92 protected $regions = array();
d4a03c00 93
94 /** @var string the region where new blocks are added.*/
95 protected $defaultregion = null;
96
97 /** @var array will be $DB->get_records('blocks') */
98 protected $allblocks = null;
99
100 /**
101 * @var array blocks that this user can add to this page. Will be a subset
a2789e34 102 * of $allblocks, but with array keys block->name. Access this via the
103 * {@link get_addable_blocks()} method to ensure it is lazy-loaded.
d4a03c00 104 */
105 protected $addableblocks = null;
08eab897 106
bb46a4fa 107 /**
108 * Will be an array region-name => array(db rows loaded in load_blocks);
d4accfc0 109 * @var array
bb46a4fa 110 */
111 protected $birecordsbyregion = null;
112
113 /**
114 * array region-name => array(block objects); populated as necessary by
115 * the ensure_instances_exist method.
d4accfc0 116 * @var array
bb46a4fa 117 */
118 protected $blockinstances = array();
119
120 /**
d4a03c00 121 * array region-name => array(block_contents objects) what acutally needs to
bb46a4fa 122 * be displayed in each region.
d4accfc0 123 * @var array
bb46a4fa 124 */
125 protected $visibleblockcontent = array();
08eab897 126
d4a03c00 127 /**
128 * array region-name => array(block_contents objects) extra block-like things
129 * to be displayed in each region, before the real blocks.
130 * @var array
131 */
132 protected $extracontent = array();
133
86b5ea0f 134/// Constructor ================================================================
135
136 /**
137 * Constructor.
138 * @param object $page the moodle_page object object we are managing the blocks for,
139 * or a reasonable faxilimily. (See the comment at the top of this classe
d4accfc0 140 * and {@link http://en.wikipedia.org/wiki/Duck_typing})
86b5ea0f 141 */
142 public function __construct($page) {
143 $this->page = $page;
144 }
145
146/// Getter methods =============================================================
147
148 /**
d4accfc0 149 * Get an array of all region names on this page where a block may appear
150 *
86b5ea0f 151 * @return array the internal names of the regions on this page where block may appear.
152 */
153 public function get_regions() {
d4a03c00 154 $this->page->initialise_theme_and_output();
86b5ea0f 155 return array_keys($this->regions);
156 }
157
158 /**
d4accfc0 159 * Get the region name of the region blocks are added to by default
160 *
86b5ea0f 161 * @return string the internal names of the region where new blocks are added
162 * by default, and where any blocks from an unrecognised region are shown.
163 * (Imagine that blocks were added with one theme selected, then you switched
164 * to a theme with different block positions.)
165 */
166 public function get_default_region() {
d4a03c00 167 $this->page->initialise_theme_and_output();
86b5ea0f 168 return $this->defaultregion;
169 }
170
08eab897 171 /**
172 * The list of block types that may be added to this page.
d4accfc0 173 *
727ae436 174 * @return array block name => record from block table.
08eab897 175 */
176 public function get_addable_blocks() {
177 $this->check_is_loaded();
178
179 if (!is_null($this->addableblocks)) {
180 return $this->addableblocks;
181 }
182
183 // Lazy load.
184 $this->addableblocks = array();
185
186 $allblocks = blocks_get_record();
187 if (empty($allblocks)) {
188 return $this->addableblocks;
189 }
190
bb46a4fa 191 $pageformat = $this->page->pagetype;
08eab897 192 foreach($allblocks as $block) {
193 if ($block->visible &&
bb46a4fa 194 (block_method_result($block->name, 'instance_allow_multiple') || !$this->is_block_present($block->id)) &&
a2789e34 195 blocks_name_allowed_in_format($block->name, $pageformat) &&
196 block_method_result($block->name, 'user_can_addto', $this->page)) {
197 $this->addableblocks[$block->name] = $block;
08eab897 198 }
199 }
200
201 return $this->addableblocks;
202 }
203
d4accfc0 204 /**
205 * Find out if a block is present ? just a guess
206 * @todo Write this function and document
207 */
08eab897 208 public function is_block_present($blocktypeid) {
209 // TODO
210 }
211
212 /**
d4accfc0 213 * Find out if a block type is known by the system
214 *
08eab897 215 * @param string $blockname the name of ta type of block.
216 * @param boolean $includeinvisible if false (default) only check 'visible' blocks, that is, blocks enabled by the admin.
217 * @return boolean true if this block in installed.
218 */
219 public function is_known_block_type($blockname, $includeinvisible = false) {
220 $blocks = $this->get_installed_blocks();
221 foreach ($blocks as $block) {
222 if ($block->name == $blockname && ($includeinvisible || $block->visible)) {
223 return true;
224 }
225 }
226 return false;
227 }
228
229 /**
d4accfc0 230 * Find out if a region exists on a page
231 *
08eab897 232 * @param string $region a region name
233 * @return boolean true if this retion exists on this page.
234 */
235 public function is_known_region($region) {
236 return array_key_exists($region, $this->regions);
237 }
238
239 /**
d4accfc0 240 * Get an array of all blocks within a given region
241 *
242 * @param string $region a block region that exists on this page.
08eab897 243 * @return array of block instances.
244 */
245 public function get_blocks_for_region($region) {
246 $this->check_is_loaded();
bb46a4fa 247 $this->ensure_instances_exist($region);
248 return $this->blockinstances[$region];
249 }
250
251 /**
d4accfc0 252 * Returns an array of block content objects that exist in a region
253 *
d4a03c00 254 * @param string $region a block region that exists on this page.
255 * @return array of block block_contents objects for all the blocks in a region.
bb46a4fa 256 */
d4a03c00 257 public function get_content_for_region($region, $output) {
bb46a4fa 258 $this->check_is_loaded();
d4a03c00 259 $this->ensure_content_created($region, $output);
bb46a4fa 260 return $this->visibleblockcontent[$region];
08eab897 261 }
262
d4a03c00 263 /**
264 * Determine whether a region contains anything. (Either any real blocks, or
265 * the add new block UI.)
78d27a90 266 *
267 * (You may wonder why the $output parameter is required. Unfortunately,
268 * becuase of the way that blocks work, the only reliable way to find out
269 * if a block will be visible is to get the content for output, and to
270 * get the content, you need a renderer. Fortunately, this is not a
271 * performance problem, becuase we cache the output that is generated, and
272 * in almost every case where we call region_has_content, we are about to
273 * output the blocks anyway, so we are not doing wasted effort.)
274 *
d4a03c00 275 * @param string $region a block region that exists on this page.
78d27a90 276 * @param object $output a moodle_core_renderer. normally the global $OUTPUT.
d4a03c00 277 * @return boolean Whether there is anything in this region.
278 */
78d27a90 279 public function region_has_content($region, $output) {
d4a03c00 280 if (!$this->is_known_region($region)) {
281 return false;
282 }
283 $this->check_is_loaded();
78d27a90 284 $this->ensure_content_created($region, $output);
d4a03c00 285 if ($this->page->user_is_editing() && $this->page->user_can_edit_blocks()) {
286 // If editing is on, we need all the block regions visible, for the
287 // move blocks UI.
288 return true;
289 }
78d27a90 290 return !empty($this->visibleblockcontent[$region]) || !empty($this->extracontent[$region]);
d4a03c00 291 }
292
08eab897 293 /**
d4accfc0 294 * Get an array of all of the installed blocks.
295 *
08eab897 296 * @return array contents of the block table.
297 */
298 public function get_installed_blocks() {
299 global $DB;
300 if (is_null($this->allblocks)) {
301 $this->allblocks = $DB->get_records('block');
302 }
303 return $this->allblocks;
304 }
305
86b5ea0f 306/// Setter methods =============================================================
307
308 /**
d4accfc0 309 * Add a region to a page
310 *
86b5ea0f 311 * @param string $region add a named region where blocks may appear on the
312 * current page. This is an internal name, like 'side-pre', not a string to
313 * display in the UI.
314 */
315 public function add_region($region) {
316 $this->check_not_yet_loaded();
317 $this->regions[$region] = 1;
318 }
319
320 /**
d4accfc0 321 * Add an array of regions
322 * @see add_region()
323 *
86b5ea0f 324 * @param array $regions this utility method calls add_region for each array element.
325 */
326 public function add_regions($regions) {
327 foreach ($regions as $region) {
328 $this->add_region($region);
329 }
330 }
331
332 /**
d4accfc0 333 * Set the default region for new blocks on the page
334 *
86b5ea0f 335 * @param string $defaultregion the internal names of the region where new
336 * blocks should be added by default, and where any blocks from an
337 * unrecognised region are shown.
338 */
339 public function set_default_region($defaultregion) {
340 $this->check_not_yet_loaded();
08eab897 341 $this->check_region_is_known($defaultregion);
86b5ea0f 342 $this->defaultregion = $defaultregion;
343 }
344
d4a03c00 345 /**
346 * Add something that looks like a block, but which isn't an actual block_instance,
347 * to this page.
348 *
349 * @param block_contents $bc the content of the block like thing.
350 * @param string $region a block region that exists on this page.
351 */
352 public function add_pretend_block($bc, $region) {
353 $this->page->initialise_theme_and_output();
354 $this->check_region_is_known($region);
355 if (array_key_exists($region, $this->visibleblockcontent)) {
356 throw new coding_exception('block_manager has already prepared the blocks in region ' .
357 $region . 'for output. It is too late to add a pretend block.');
358 }
359 $this->extracontent[$region][] = $bc;
360 }
361
08eab897 362/// Actions ====================================================================
363
364 /**
365 * This method actually loads the blocks for our page from the database.
d4accfc0 366 *
ae42ff6f 367 * @param boolean|null $includeinvisible
368 * null (default) - load hidden blocks if $this->page->user_is_editing();
369 * true - load hidden blocks.
370 * false - don't load hidden blocks.
08eab897 371 */
ae42ff6f 372 public function load_blocks($includeinvisible = null) {
d19e8195 373 global $DB, $CFG;
bb46a4fa 374 if (!is_null($this->birecordsbyregion)) {
375 // Already done.
376 return;
377 }
08eab897 378
d19e8195 379 if ($CFG->version < 2009050619) {
380 // Upgrade/install not complete. Don't try too show any blocks.
381 $this->birecordsbyregion = array();
382 return;
383 }
384
d4a03c00 385 // Ensure we have been initialised.
b7009474 386 if (!isset($this->defaultregion)) {
387 $this->page->initialise_theme_and_output();
d4a03c00 388 // If there are still no block regions, then there are no blocks on this page.
389 if (empty($this->regions)) {
390 $this->birecordsbyregion = array();
391 return;
392 }
b7009474 393 }
394
1d13c75c 395 // The code here needs to be consistent with the code in block_load_for_page.
08eab897 396 if (is_null($includeinvisible)) {
397 $includeinvisible = $this->page->user_is_editing();
398 }
399 if ($includeinvisible) {
08eab897 400 $visiblecheck = '';
ae42ff6f 401 } else {
402 $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)';
08eab897 403 }
404
405 $context = $this->page->context;
13a0d3d3 406 $contexttest = 'bi.parentcontextid = :contextid2';
08eab897 407 $parentcontextparams = array();
408 $parentcontextids = get_parent_contexts($context);
409 if ($parentcontextids) {
410 list($parentcontexttest, $parentcontextparams) =
411 $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000');
13a0d3d3 412 $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.parentcontextid $parentcontexttest))";
08eab897 413 }
414
1d13c75c 415 $pagetypepatterns = matching_page_type_patterns($this->page->pagetype);
08eab897 416 list($pagetypepatterntest, $pagetypepatternparams) =
417 $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000');
418
419 $params = array(
420 'subpage1' => $this->page->subpage,
421 'subpage2' => $this->page->subpage,
422 'contextid1' => $context->id,
423 'contextid2' => $context->id,
424 'pagetype' => $this->page->pagetype,
e92c286c 425 'contextblock' => CONTEXT_BLOCK,
08eab897 426 );
427 $sql = "SELECT
428 bi.id,
d4a03c00 429 bp.id AS blockpositionid,
08eab897 430 bi.blockname,
13a0d3d3 431 bi.parentcontextid,
08eab897 432 bi.showinsubcontexts,
433 bi.pagetypepattern,
434 bi.subpagepattern,
ae42ff6f 435 bi.defaultregion,
436 bi.defaultweight,
bb46a4fa 437 COALESCE(bp.visible, 1) AS visible,
08eab897 438 COALESCE(bp.region, bi.defaultregion) AS region,
439 COALESCE(bp.weight, bi.defaultweight) AS weight,
e92c286c 440 bi.configdata,
441 ctx.id AS ctxid,
442 ctx.path AS ctxpath,
443 ctx.depth AS ctxdepth,
444 ctx.contextlevel AS ctxlevel
08eab897 445
446 FROM {block_instances} bi
447 JOIN {block} b ON bi.blockname = b.name
448 LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id
449 AND bp.contextid = :contextid1
450 AND bp.pagetype = :pagetype
451 AND bp.subpage = :subpage1
e92c286c 452 JOIN {context} ctx ON ctx.contextlevel = :contextblock
453 AND ctx.instanceid = bi.id
08eab897 454
455 WHERE
456 $contexttest
457 AND bi.pagetypepattern $pagetypepatterntest
458 AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)
459 $visiblecheck
460 AND b.visible = 1
461
462 ORDER BY
463 COALESCE(bp.region, bi.defaultregion),
464 COALESCE(bp.weight, bi.defaultweight),
465 bi.id";
466 $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams);
467
bb46a4fa 468 $this->birecordsbyregion = $this->prepare_per_region_arrays();
08eab897 469 $unknown = array();
08eab897 470 foreach ($blockinstances as $bi) {
e92c286c 471 $bi = make_context_subobj($bi);
08eab897 472 if ($this->is_known_region($bi->region)) {
bb46a4fa 473 $this->birecordsbyregion[$bi->region][] = $bi;
08eab897 474 } else {
475 $unknown[] = $bi;
476 }
477 }
d4a03c00 478
479 // Pages don't necessarily have a defaultregion. The one time this can
480 // happen is when there are no theme block regions, but the script itself
481 // has a block region in the main content area.
482 if (!empty($this->defaultregion)) {
483 $this->birecordsbyregion[$this->defaultregion] =
484 array_merge($this->birecordsbyregion[$this->defaultregion], $unknown);
485 }
08eab897 486 }
487
488 /**
489 * Add a block to the current page, or related pages. The block is added to
490 * context $this->page->contextid. If $pagetypepattern $subpagepattern
d4accfc0 491 *
08eab897 492 * @param string $blockname The type of block to add.
493 * @param string $region the block region on this page to add the block to.
494 * @param integer $weight determines the order where this block appears in the region.
495 * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context.
496 * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type.
497 * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage.
498 */
499 public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) {
500 global $DB;
501 $this->check_known_block_type($blockname);
502 $this->check_region_is_known($region);
503
504 if (empty($pagetypepattern)) {
505 $pagetypepattern = $this->page->pagetype;
506 }
507
508 $blockinstance = new stdClass;
509 $blockinstance->blockname = $blockname;
13a0d3d3 510 $blockinstance->parentcontextid = $this->page->context->id;
08eab897 511 $blockinstance->showinsubcontexts = !empty($showinsubcontexts);
512 $blockinstance->pagetypepattern = $pagetypepattern;
513 $blockinstance->subpagepattern = $subpagepattern;
514 $blockinstance->defaultregion = $region;
515 $blockinstance->defaultweight = $weight;
516 $blockinstance->configdata = '';
feed1900 517 $blockinstance->id = $DB->insert_record('block_instances', $blockinstance);
518
e92c286c 519 // Ensure the block context is created.
520 get_context_instance(CONTEXT_BLOCK, $blockinstance->id);
e03c0c1d 521
feed1900 522 // If the new instance was created, allow it to do additional setup
e92c286c 523 if ($block = block_instance($blockname, $blockinstance)) {
feed1900 524 $block->instance_create();
525 }
08eab897 526 }
527
21d33bdf 528 public function add_block_at_end_of_default_region($blockname) {
529 $defaulregion = $this->get_default_region();
2a3b0763 530
21d33bdf 531 $lastcurrentblock = end($this->birecordsbyregion[$defaulregion]);
2a3b0763 532 if ($lastcurrentblock) {
533 $weight = $lastcurrentblock->weight + 1;
534 } else {
535 $weight = 0;
536 }
537
21d33bdf 538 if ($this->page->subpage) {
539 $subpage = $this->page->subpage;
540 } else {
541 $subpage = null;
542 }
a2789e34 543
544 // Special case. Course view page type include the course format, but we
545 // want to add the block non-format-specifically.
546 $pagetypepattern = $this->page->pagetype;
547 if (strpos($pagetypepattern, 'course-view') === 0) {
548 $pagetypepattern = 'course-view-*';
549 }
550
2a3b0763 551 $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage);
21d33bdf 552 }
553
9d1d606e 554 /**
555 * Convenience method, calls add_block repeatedly for all the blocks in $blocks.
d4accfc0 556 *
2a3b0763 557 * @param array $blocks array with array keys the region names, and values an array of block names.
9d1d606e 558 * @param string $pagetypepattern optional. Passed to @see add_block()
559 * @param string $subpagepattern optional. Passed to @see add_block()
560 */
561 public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL) {
562 $this->add_regions(array_keys($blocks));
563 foreach ($blocks as $region => $regionblocks) {
564 $weight = 0;
565 foreach ($regionblocks as $blockname) {
566 $this->add_block($blockname, $region, $weight, false, $pagetypepattern, $subpagepattern);
567 $weight += 1;
568 }
569 }
570 }
571
f4d38d20 572 /**
d4accfc0 573 * Find a given block by its instance id
574 *
f4d38d20 575 * @param integer $instanceid
d4accfc0 576 * @return object
f4d38d20 577 */
578 public function find_instance($instanceid) {
579 foreach ($this->regions as $region => $notused) {
580 $this->ensure_instances_exist($region);
581 foreach($this->blockinstances[$region] as $instance) {
582 if ($instance->instance->id == $instanceid) {
583 return $instance;
584 }
585 }
586 }
587 throw new block_not_on_page_exception($instanceid, $this->page);
588 }
589
86b5ea0f 590/// Inner workings =============================================================
591
d4accfc0 592 /**
593 * Check whether the page blocks have been loaded yet
594 *
595 * @return void Throws coding exception if already loaded
596 */
86b5ea0f 597 protected function check_not_yet_loaded() {
bb46a4fa 598 if (!is_null($this->birecordsbyregion)) {
86b5ea0f 599 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.');
600 }
601 }
602
d4accfc0 603 /**
604 * Check whether the page blocks have been loaded yet
605 *
606 * Nearly identical to the above function {@link check_not_yet_loaded()} except different message
607 *
608 * @return void Throws coding exception if already loaded
609 */
08eab897 610 protected function check_is_loaded() {
bb46a4fa 611 if (is_null($this->birecordsbyregion)) {
08eab897 612 throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.');
613 }
614 }
615
d4accfc0 616 /**
617 * Check if a block type is known and usable
618 *
619 * @param string $blockname The block type name to search for
620 * @param bool $includeinvisible Include disabled block types in the intial pass
621 * @return void Coding Exception thrown if unknown or not enabled
622 */
08eab897 623 protected function check_known_block_type($blockname, $includeinvisible = false) {
624 if (!$this->is_known_block_type($blockname, $includeinvisible)) {
625 if ($this->is_known_block_type($blockname, true)) {
626 throw new coding_exception('Unknown block type ' . $blockname);
627 } else {
628 throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.');
629 }
630 }
631 }
632
d4accfc0 633 /**
634 * Check if a region is known by its name
635 *
636 * @param string $region
637 * @return void Coding Exception thrown if the region is not known
638 */
08eab897 639 protected function check_region_is_known($region) {
640 if (!$this->is_known_region($region)) {
641 throw new coding_exception('Trying to reference an unknown block region ' . $region);
642 }
86b5ea0f 643 }
bb46a4fa 644
645 /**
d4accfc0 646 * Returns an array of region names as keys and nested arrays for values
647 *
bb46a4fa 648 * @return array an array where the array keys are the region names, and the array
649 * values are empty arrays.
650 */
651 protected function prepare_per_region_arrays() {
652 $result = array();
653 foreach ($this->regions as $region => $notused) {
654 $result[$region] = array();
655 }
656 return $result;
657 }
658
d4accfc0 659 /**
660 * Create a set of new block instance from a record array
661 *
662 * @param array $birecords An array of block instance records
663 * @return array An array of instantiated block_instance objects
664 */
bb46a4fa 665 protected function create_block_instances($birecords) {
666 $results = array();
667 foreach ($birecords as $record) {
668 $results[] = block_instance($record->blockname, $record, $this->page);
669 }
670 return $results;
671 }
672
4578a5eb 673 /**
674 * Create all the bock instances for all the blocks that were loaded by
675 * load_blocks. This is used, for example, to ensure that all blocks get a
676 * chance to initialise themselves via the {@link block_base::specialize()}
677 * method, before any output is done.
678 */
679 public function create_all_block_instances() {
680 foreach ($this->get_regions() as $region) {
681 $this->ensure_instances_exist($region);
682 }
683 }
684
d4accfc0 685 /**
686 * Return an array of content vars from a set of block instances
687 *
688 * @param array $instances An array of block instances
689 * @return array An array of content vars
690 */
d4a03c00 691 protected function create_block_contents($instances, $output) {
bb46a4fa 692 $results = array();
693 foreach ($instances as $instance) {
d4a03c00 694 $content = $instance->get_content_for_output($output);
bb46a4fa 695 if (!empty($content)) {
696 $results[] = $content;
697 }
698 }
699 return $results;
700 }
701
d4accfc0 702 /**
703 * Ensure block instances exist for a given region
704 *
705 * @param string $region Check for bi's with the instance with this name
706 */
bb46a4fa 707 protected function ensure_instances_exist($region) {
708 $this->check_region_is_known($region);
709 if (!array_key_exists($region, $this->blockinstances)) {
710 $this->blockinstances[$region] =
711 $this->create_block_instances($this->birecordsbyregion[$region]);
712 }
713 }
714
d4accfc0 715 /**
716 * Ensure that there is some content within the given region
717 *
718 * @param string $region The name of the region to check
719 */
d4a03c00 720 protected function ensure_content_created($region, $output) {
bb46a4fa 721 $this->ensure_instances_exist($region);
722 if (!array_key_exists($region, $this->visibleblockcontent)) {
d4a03c00 723 $contents = array();
724 if (array_key_exists($region, $this->extracontent)) {
725 $contents = $this->extracontent[$region];
726 }
727 $contents = array_merge($contents, $this->create_block_contents($this->blockinstances[$region], $output));
728 if ($region == $this->defaultregion) {
21d33bdf 729 $addblockui = block_add_block_ui($this->page, $output);
d4a03c00 730 if ($addblockui) {
731 $contents[] = $addblockui;
732 }
733 }
734 $this->visibleblockcontent[$region] = $contents;
bb46a4fa 735 }
736 }
86b5ea0f 737}
738
08eab897 739/// Helper functions for working with block classes ============================
740
741/**
742 * Call a class method (one that does not requrie a block instance) on a block class.
d4accfc0 743 *
08eab897 744 * @param string $blockname the name of the block.
745 * @param string $method the method name.
746 * @param array $param parameters to pass to the method.
747 * @return mixed whatever the method returns.
748 */
11306331 749function block_method_result($blockname, $method, $param = NULL) {
0f3fe4b6 750 if(!block_load_class($blockname)) {
751 return NULL;
752 }
11306331 753 return call_user_func(array('block_'.$blockname, $method), $param);
0f3fe4b6 754}
755
1d13c75c 756/**
757 * Load a block instance, with position information about where that block appears
758 * on a given page.
759 *
760 * @param integer$blockid the block_instance.id.
761 * @param moodle_page $page the page the block is appearing on.
762 * @return block_base the requested block.
763 */
764function block_load_for_page($blockid, $page) {
765 global $DB;
766
767 // The code here needs to be consistent with the code in block_manager::load_blocks.
768 $params = array(
769 'blockinstanceid' => $blockid,
770 'subpage' => $page->subpage,
771 'contextid' => $page->context->id,
772 'pagetype' => $page->pagetype,
773 'contextblock' => CONTEXT_BLOCK,
774 );
775 $sql = "SELECT
776 bi.id,
777 bp.id AS blockpositionid,
778 bi.blockname,
779 bi.parentcontextid,
780 bi.showinsubcontexts,
781 bi.pagetypepattern,
782 bi.subpagepattern,
783 bi.defaultregion,
784 bi.defaultweight,
785 COALESCE(bp.visible, 1) AS visible,
786 COALESCE(bp.region, bi.defaultregion) AS region,
787 COALESCE(bp.weight, bi.defaultweight) AS weight,
788 bi.configdata,
789 ctx.id AS ctxid,
790 ctx.path AS ctxpath,
791 ctx.depth AS ctxdepth,
792 ctx.contextlevel AS ctxlevel
793
794 FROM {block_instances} bi
795 JOIN {block} b ON bi.blockname = b.name
796 LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id
797 AND bp.contextid = :contextid
798 AND bp.pagetype = :pagetype
799 AND bp.subpage = :subpage
800 JOIN {context} ctx ON ctx.contextlevel = :contextblock
801 AND ctx.instanceid = bi.id
802
803 WHERE
804 bi.id = :blockinstanceid
805 AND b.visible = 1
806
807 ORDER BY
808 COALESCE(bp.region, bi.defaultregion),
809 COALESCE(bp.weight, bi.defaultweight),
810 bi.id";
811 $bi = $DB->get_record_sql($sql, $params, MUST_EXIST);
812 $bi = make_context_subobj($bi);
813 return block_instance($bi->blockname, $bi, $page);
814}
815
08eab897 816/**
817 * Creates a new object of the specified block class.
d4accfc0 818 *
08eab897 819 * @param string $blockname the name of the block.
820 * @param $instance block_instances DB table row (optional).
bb46a4fa 821 * @param moodle_page $page the page this block is appearing on.
08eab897 822 * @return block_base the requested block instance.
823 */
bb46a4fa 824function block_instance($blockname, $instance = NULL, $page = NULL) {
0f3fe4b6 825 if(!block_load_class($blockname)) {
826 return false;
827 }
e89d741a 828 $classname = 'block_'.$blockname;
f032aa7a 829 $retval = new $classname;
9b4b78fd 830 if($instance !== NULL) {
bb46a4fa 831 if (is_null($page)) {
832 global $PAGE;
833 $page = $PAGE;
834 }
835 $retval->_load_instance($instance, $page);
9b4b78fd 836 }
837 return $retval;
0f3fe4b6 838}
839
08eab897 840/**
841 * Load the block class for a particular type of block.
d4accfc0 842 *
08eab897 843 * @param string $blockname the name of the block.
844 * @return boolean success or failure.
845 */
0f3fe4b6 846function block_load_class($blockname) {
847 global $CFG;
848
a9033ad5 849 if(empty($blockname)) {
c7a9e293 850 return false;
851 }
852
e89d741a 853 $classname = 'block_'.$blockname;
a9033ad5 854
855 if(class_exists($classname)) {
856 return true;
857 }
858
859 require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
e9a20759 860 @include_once($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'); // do not throw errors if block code not present
0f3fe4b6 861
0f3fe4b6 862 return class_exists($classname);
863}
864
1d13c75c 865/**
866 * Given a specific page type, return all the page type patterns that might
867 * match it.
868 *
869 * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'.
870 * @return array an array of all the page type patterns that might match this page type.
871 */
872function matching_page_type_patterns($pagetype) {
873 $patterns = array($pagetype);
874 $bits = explode('-', $pagetype);
875 if (count($bits) == 3 && $bits[0] == 'mod') {
876 if ($bits[2] == 'view') {
877 $patterns[] = 'mod-*-view';
878 } else if ($bits[2] == 'index') {
879 $patterns[] = 'mod-*-index';
880 }
881 }
882 while (count($bits) > 0) {
883 $patterns[] = implode('-', $bits) . '-*';
884 array_pop($bits);
885 }
886 $patterns[] = '*';
887 return $patterns;
888}
889
21d33bdf 890/// Functions update the blocks if required by the request parameters ==========
891
892/**
893 * Return a {@link block_contents} representing the add a new block UI, if
894 * this user is allowed to see it.
895 *
896 * @return block_contents an appropriate block_contents, or null if the user
897 * cannot add any blocks here.
898 */
899function block_add_block_ui($page, $output) {
900 global $CFG;
901 if (!$page->user_is_editing() || !$page->user_can_edit_blocks()) {
902 return null;
903 }
904
905 $bc = new block_contents();
906 $bc->title = get_string('addblock');
907 $bc->add_class('block_adminblock');
908
a2789e34 909 $missingblocks = $page->blocks->get_addable_blocks();
21d33bdf 910 if (empty($missingblocks)) {
a2789e34 911 $bc->content = get_string('noblockstoaddhere');
21d33bdf 912 return $bc;
913 }
914
915 $menu = array();
a2789e34 916 foreach ($missingblocks as $block) {
21d33bdf 917 $blockobject = block_instance($block->name);
918 if ($blockobject !== false && $blockobject->user_can_addto($page)) {
919 $menu[$block->name] = $blockobject->get_title();
920 }
921 }
922 asort($menu, SORT_LOCALE_STRING);
923
924 // TODO convert to $OUTPUT.
a2789e34 925 $actionurl = $page->url->out_action() . '&amp;bui_addblock=';
21d33bdf 926 $bc->content = popup_form($actionurl, $menu, 'add_block', '', get_string('adddots'), '', '', true);
927 return $bc;
928}
929
1936f20b 930/**
931 * Get the appropriate list of editing icons for a block. This is used
932 * to set {@link block_contents::$controls} in {@link block_base::get_contents_for_output()}.
933 *
934 * @param $output The core_renderer to use when generating the output. (Need to get icon paths.)
935 * @return an array in the format for {@link block_contents::$controls}
936 * @since Moodle 2.0.
937 */
938function block_edit_controls($block, $page) {
939 global $CFG;
940
941 $controls = array();
942 $actionurl = $page->url->out_action();
943
944 // Assign roles icon.
945 if (has_capability('moodle/role:assign', $block->context)) {
4a3b4620 946 $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
1d13c75c 947 '/roles/assign.php?contextid=' . $block->context->id . '&amp;returnurl=' . urlencode($page->url->out_returnurl()),
1936f20b 948 'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'));
949 }
950
951 if ($block->user_can_edit() && $page->user_can_edit_blocks()) {
952 // Show/hide icon.
953 if ($block->instance->visible) {
ae42ff6f 954 $controls[] = array('url' => $actionurl . '&amp;bui_hideid=' . $block->instance->id,
1936f20b 955 'icon' => 't/hide', 'caption' => get_string('hide'));
956 } else {
ae42ff6f 957 $controls[] = array('url' => $actionurl . '&amp;bui_showid=' . $block->instance->id,
1936f20b 958 'icon' => 't/show', 'caption' => get_string('show'));
959 }
960
73e2e5c0 961 // Edit config icon - always show - needed for positioning UI.
962 $controls[] = array('url' => block_edit_url($block, $page)->out(),
963 'icon' => 't/edit', 'caption' => get_string('configuration'));
1936f20b 964
965 // Delete icon.
966 if ($block->user_can_addto($page)) {
967 $controls[] = array('url' => $actionurl . '&amp;bui_deleteid=' . $block->instance->id,
968 'icon' => 't/delete', 'caption' => get_string('delete'));
969 }
970
971 // Move icon.
972 $controls[] = array('url' => $page->url->out(false, array('moveblockid' => $block->instance->id)),
973 'icon' => 't/move', 'caption' => get_string('move'));
974 }
975
976 return $controls;
977}
978
1d13c75c 979/**
980 * Get the URL for editing a particular block instance.
981 * @param block_base $block a block object.
982 * @return moodle_url the url.
983 */
984function block_edit_url($block, $page) {
985 global $CFG;
986 $urlparams = array(
987 'id' => $block->instance->id,
988 'pagecontextid' => $page->context->id,
989 'pagetype' => $page->pagetype,
990 'returnurl' => $page->url->out_returnurl(),
991 );
992 if ($page->subpage) {
993 $urlparams['subpage'] = $page->subpage;
994 }
995 return new moodle_url($CFG->wwwroot . '/blocks/edit.php', $urlparams);
996}
997
21d33bdf 998/**
999 * Process any block actions that were specified in the URL.
1000 *
1001 * This can only be done given a valid $page object.
1002 *
a2789e34 1003 * @param moodle_page $page the page to add blocks to.
21d33bdf 1004 * @return boolean true if anything was done. False if not.
1005 */
1006function block_process_url_actions($page) {
a2789e34 1007 return block_process_url_add($page) ||
1008 block_process_url_delete($page) ||
1009 block_process_url_show_hide($page);
21d33bdf 1010}
1011
1012/**
a2789e34 1013 * Handle adding a block.
1014 * @param moodle_page $page the page to add blocks to.
21d33bdf 1015 * @return boolean true if anything was done. False if not.
1016 */
1017function block_process_url_add($page) {
1018 $blocktype = optional_param('bui_addblock', null, PARAM_SAFEDIR);
1019 if (!$blocktype) {
1020 return false;
1021 }
1022
727ae436 1023 confirm_sesskey();
1024
a2789e34 1025 if (!$page->user_is_editing() && !$page->user_can_edit_blocks()) {
1026 throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('addblock'));
1027 }
1028
1029 if (!array_key_exists($blocktype, $page->blocks->get_addable_blocks())) {
1030 throw new moodle_exception('cannotaddthisblocktype', '', $page->url->out(), $blocktype);
1031 }
1032
21d33bdf 1033 $page->blocks->add_block_at_end_of_default_region($blocktype);
2a3b0763 1034
727ae436 1035 // If the page URL was a guses, it will contain the bui_... param, so we must make sure it is not there.
1036 $page->ensure_param_not_in_url('bui_addblock');
2a3b0763 1037
21d33bdf 1038 return true;
1039}
1040
a2789e34 1041/**
1042 * Handle deleting a block.
1043 * @param moodle_page $page the page to add blocks to.
1044 * @return boolean true if anything was done. False if not.
1045 */
1046function block_process_url_delete($page) {
1047 $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER);
1048 if (!$blockid) {
1049 return false;
1050 }
1051
727ae436 1052 confirm_sesskey();
1053
02b126af 1054 $block = $page->blocks->find_instance($blockid);
1055
1056 if (!$block->user_can_edit() || !$page->user_can_edit_blocks() || !$block->user_can_addto($page)) {
1057 throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('deleteablock'));
1058 }
1059
1060 blocks_delete_instance($block->instance);
2a3b0763 1061
727ae436 1062 // If the page URL was a guses, it will contain the bui_... param, so we must make sure it is not there.
1063 $page->ensure_param_not_in_url('bui_deleteid');
2a3b0763 1064
a2789e34 1065 return true;
1066}
21d33bdf 1067
a2789e34 1068/**
1069 * Handle showing or hiding a block.
1070 * @param moodle_page $page the page to add blocks to.
1071 * @return boolean true if anything was done. False if not.
1072 */
1073function block_process_url_show_hide($page) {
ae42ff6f 1074 if ($blockid = optional_param('bui_hideid', null, PARAM_INTEGER)) {
1075 $newvisibility = 0;
1076 } else if ($blockid = optional_param('bui_showid', null, PARAM_INTEGER)) {
1077 $newvisibility = 1;
1078 } else {
1079 return false;
1080 }
1081
1082 confirm_sesskey();
1083
1084 $block = $page->blocks->find_instance($blockid);
1085
1086 if (!$block->user_can_edit() || !$page->user_can_edit_blocks()) {
1087 throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('hideshowblocks'));
1088 }
1089
1090 blocks_set_visibility($block->instance, $page, $newvisibility);
1091
1092 // If the page URL was a guses, it will contain the bui_... param, so we must make sure it is not there.
1093 $page->ensure_param_not_in_url('bui_hideid');
1094 $page->ensure_param_not_in_url('bui_showid');
1095
1096 return true;
a2789e34 1097}
1098
1099///**
1100// * Handle deleting a block.
1101// * @param moodle_page $page the page to add blocks to.
1102// * @return boolean true if anything was done. False if not.
1103// */
1104//function block_process_url_delete($page) {
1105//
1106//}
21d33bdf 1107
1108// Functions that have been deprecated by block_manager =======================
f032aa7a 1109
08eab897 1110/**
a2789e34 1111 * @deprecated since Moodle 2.0 - use $page->blocks->get_addable_blocks();
d4accfc0 1112 *
08eab897 1113 * This function returns an array with the IDs of any blocks that you can add to your page.
1114 * Parameters are passed by reference for speed; they are not modified at all.
d4accfc0 1115 *
08eab897 1116 * @param $page the page object.
bb46a4fa 1117 * @param $blockmanager Not used.
08eab897 1118 * @return array of block type ids.
1119 */
bb46a4fa 1120function blocks_get_missing(&$page, &$blockmanager) {
a2789e34 1121 debugging('blocks_get_missing is deprecated. Please use $page->blocks->get_addable_blocks() instead.', DEBUG_DEVELOPER);
1122 $blocks = $page->blocks->get_addable_blocks();
1123 $ids = array();
1124 foreach ($blocks as $block) {
1125 $ids[] = $block->id;
1126 }
1127 return $ids;
f032aa7a 1128}
1129
bb46a4fa 1130/**
1131 * Actually delete from the database any blocks that are currently on this page,
1132 * but which should not be there according to blocks_name_allowed_in_format.
d4accfc0 1133 *
1134 * @todo Write/Fix this function. Currently returns immediatly
c679c358 1135 * @param $course
bb46a4fa 1136 */
c679c358 1137function blocks_remove_inappropriate($course) {
bb46a4fa 1138 // TODO
1139 return;
1140 $blockmanager = blocks_get_by_page($page);
f032aa7a 1141
bb46a4fa 1142 if(empty($blockmanager)) {
f032aa7a 1143 return;
1144 }
1145
d529807a 1146 if(($pageformat = $page->pagetype) == NULL) {
f032aa7a 1147 return;
1148 }
1149
f2c6739c 1150 foreach($blockmanager as $region) {
1151 foreach($region as $instance) {
f032aa7a 1152 $block = blocks_get_record($instance->blockid);
5bbbe0be 1153 if(!blocks_name_allowed_in_format($block->name, $pageformat)) {
a2789e34 1154 blocks_delete_instance($instance->instance);
f032aa7a 1155 }
1156 }
1157 }
1158}
1159
d4accfc0 1160/**
1161 * Check that a given name is in a permittable format
1162 *
1163 * @param string $name
1164 * @param string $pageformat
1165 * @return bool
1166 */
5bbbe0be 1167function blocks_name_allowed_in_format($name, $pageformat) {
cd2bc3c9 1168 $accept = NULL;
1169 $maxdepth = -1;
1170 $formats = block_method_result($name, 'applicable_formats');
1171 if (!$formats) {
1172 $formats = array();
1173 }
1174 foreach ($formats as $format => $allowed) {
1175 $formatregex = '/^'.str_replace('*', '[^-]*', $format).'.*$/';
1176 $depth = substr_count($format, '-');
1177 if (preg_match($formatregex, $pageformat) && $depth > $maxdepth) {
1178 $maxdepth = $depth;
1179 $accept = $allowed;
5bbbe0be 1180 }
1181 }
cd2bc3c9 1182 if ($accept === NULL) {
5bbbe0be 1183 $accept = !empty($formats['all']);
1184 }
1185 return $accept;
1186}
1187
feed1900 1188/**
1189 * Delete a block, and associated data.
d4accfc0 1190 *
feed1900 1191 * @param object $instance a row from the block_instances table
d4accfc0 1192 * @param bool $nolongerused legacy parameter. Not used, but kept for bacwards compatibility.
1193 * @param bool $skipblockstables for internal use only. Makes @see blocks_delete_all_for_context() more efficient.
feed1900 1194 */
1195function blocks_delete_instance($instance, $nolongerused = false, $skipblockstables = false) {
f4d38d20 1196 global $DB;
1197
1198 if ($block = block_instance($instance->blockname, $instance)) {
feed1900 1199 $block->instance_delete();
1200 }
1201 delete_context(CONTEXT_BLOCK, $instance->id);
f032aa7a 1202
feed1900 1203 if (!$skipblockstables) {
1204 $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id));
1205 $DB->delete_records('block_instances', array('id' => $instance->id));
b33dd23a 1206 }
feed1900 1207}
b33dd23a 1208
feed1900 1209/**
1210 * Delete all the blocks that belong to a particular context.
d4accfc0 1211 *
d4accfc0 1212 * @param int $contextid the context id.
feed1900 1213 */
1214function blocks_delete_all_for_context($contextid) {
1215 global $DB;
a2789e34 1216 $instances = $DB->get_recordset('block_instances', array('parentcontextid' => $contextid));
feed1900 1217 foreach ($instances as $instance) {
1218 blocks_delete_instance($instance, true);
0d6b9d4f 1219 }
feed1900 1220 $instances->close();
13a0d3d3 1221 $DB->delete_records('block_instances', array('parentcontextid' => $contextid));
feed1900 1222 $DB->delete_records('block_positions', array('contextid' => $contextid));
f032aa7a 1223}
1224
ae42ff6f 1225/**
1226 * Set a block to be visible or hidden on a particular page.
1227 *
1228 * @param object $instance a row from the block_instances, preferably LEFT JOINed with the
1229 * block_positions table as return by block_manager.
1230 * @param moodle_page $page the back to set the visibility with respect to.
1231 * @param integer $newvisibility 1 for visible, 0 for hidden.
1232 */
1233function blocks_set_visibility($instance, $page, $newvisibility) {
1234 global $DB;
1235 if (!empty($instance->blockpositionid)) {
1236 // Already have local information on this page.
1237 $DB->set_field('block_positions', 'visible', $newvisibility, array('id' => $instance->blockpositionid));
1238 return;
1239 }
1240
1241 // Create a new block_positions record.
1242 $bp = new stdClass;
1243 $bp->blockinstanceid = $instance->id;
1244 $bp->contextid = $page->context->id;
1245 $bp->pagetype = $page->pagetype;
1246 if ($page->subpage) {
1247 $bp->subpage = $page->subpage;
1248 }
1249 $bp->visible = $newvisibility;
1250 $bp->region = $instance->defaultregion;
1251 $bp->weight = $instance->defaultweight;
1252 $DB->insert_record('block_positions', $bp);
1253}
1254
d4accfc0 1255/**
d4a03c00 1256 * @deprecated since 2.0
1257 * Delete all the blocks from a particular page.
d4accfc0 1258 *
d4a03c00 1259 * @param string $pagetype the page type.
1260 * @param integer $pageid the page id.
1261 * @return bool success or failure.
d4accfc0 1262 */
d4a03c00 1263function blocks_delete_all_on_page($pagetype, $pageid) {
1264 global $DB;
1265
1266 debugging('Call to deprecated function blocks_delete_all_on_page. ' .
1267 'This function cannot work any more. Doing nothing. ' .
1268 'Please update your code to use a block_manager method $PAGE->blocks->....', DEBUG_DEVELOPER);
1269 return false;
0f3fe4b6 1270}
1271
d4accfc0 1272/**
d4a03c00 1273 * Dispite what this function is called, it seems to be mostly used to populate
1274 * the default blocks when a new course (or whatever) is created.
d4accfc0 1275 *
d4a03c00 1276 * @deprecated since 2.0
d4accfc0 1277 *
d4a03c00 1278 * @param object $page the page to add default blocks to.
1279 * @return boolean success or failure.
d4accfc0 1280 */
d4a03c00 1281function blocks_repopulate_page($page) {
1282 global $CFG;
0f3fe4b6 1283
d4a03c00 1284 debugging('Call to deprecated function blocks_repopulate_page. ' .
1285 'Use a more specific method like blocks_add_default_course_blocks, ' .
1286 'or just call $PAGE->blocks->add_blocks()', DEBUG_DEVELOPER);
d23157d8 1287
d4a03c00 1288 /// If the site override has been defined, it is the only valid one.
1289 if (!empty($CFG->defaultblocks_override)) {
1290 $blocknames = $CFG->defaultblocks_override;
1291 } else {
1292 $blocknames = $page->blocks_get_default();
66492322 1293 }
0f3fe4b6 1294
d4a03c00 1295 $blocks = blocks_parse_default_blocks_list($blocknames);
1296 $page->blocks->add_blocks($blocks);
1297
1298 return true;
0f3fe4b6 1299}
1300
08eab897 1301/**
d4a03c00 1302 * Get the block record for a particular blockid - that is, a particul type os block.
d4accfc0 1303 *
d4accfc0 1304 * @param $int blockid block type id. If null, an array of all block types is returned.
1305 * @param bool $notusedanymore No longer used.
08eab897 1306 * @return array|object row from block table, or all rows.
1307 */
1308function blocks_get_record($blockid = NULL, $notusedanymore = false) {
1309 global $PAGE;
1310 $blocks = $PAGE->blocks->get_installed_blocks();
1311 if ($blockid === NULL) {
1312 return $blocks;
1313 } else if (isset($blocks[$blockid])) {
1314 return $blocks[$blockid];
1315 } else {
1316 return false;
9b4b78fd 1317 }
9b4b78fd 1318}
1319
d4accfc0 1320/**
1321 * Find a given block by its blockid within a provide array
1322 *
1323 * @param int $blockid
1324 * @param array $blocksarray
1325 * @return bool|object Instance if found else false
1326 */
9b4b78fd 1327function blocks_find_block($blockid, $blocksarray) {
0d6b9d4f 1328 if (empty($blocksarray)) {
1329 return false;
1330 }
9b4b78fd 1331 foreach($blocksarray as $blockgroup) {
0d6b9d4f 1332 if (empty($blockgroup)) {
1333 continue;
1334 }
9b4b78fd 1335 foreach($blockgroup as $instance) {
1336 if($instance->blockid == $blockid) {
1337 return $instance;
1338 }
1339 }
1340 }
1341 return false;
1342}
1343
d4accfc0 1344/**
d4a03c00 1345 * TODO Document this function, description
d4accfc0 1346 *
d4accfc0 1347 * @param object $page The page object
1348 * @param object $blockmanager The block manager object
1349 * @param string $blockaction One of [config, add, delete]
1350 * @param int|object $instanceorid The instance id or a block_instance object
1351 * @param bool $pinned
1352 * @param bool $redirect To redirect or not to that is the question but you should stick with true
1353 */
bb46a4fa 1354function blocks_execute_action($page, &$blockmanager, $blockaction, $instanceorid, $pinned=false, $redirect=true) {
58ff964f 1355 global $CFG, $USER, $DB;
9b4b78fd 1356
feed1900 1357 if (!in_array($blockaction, array('config', 'add', 'delete'))) {
1358 throw new moodle_exception('Sorry, blocks editing is currently broken. Will be fixed. See MDL-19010.');
1359 }
1360
a9c75a9c 1361 if (is_int($instanceorid)) {
9b4b78fd 1362 $blockid = $instanceorid;
a9c75a9c 1363 } else if (is_object($instanceorid)) {
9b4b78fd 1364 $instance = $instanceorid;
1365 }
0f3fe4b6 1366
1367 switch($blockaction) {
9b4b78fd 1368 case 'config':
11306331 1369 // First of all check to see if the block wants to be edited
e03c0c1d 1370 if(!$instance->user_can_edit()) {
11306331 1371 break;
9b4b78fd 1372 }
11306331 1373
e82d6cac 1374 // Now get the title and AFTER that load up the instance
e03c0c1d 1375 $blocktitle = $instance->get_title();
afd1ec02 1376
27ec21a0 1377 // Define the data we're going to silently include in the instance config form here,
9b4b78fd 1378 // so we can strip them from the submitted data BEFORE serializing it.
1379 $hiddendata = array(
19f5b2db 1380 'sesskey' => sesskey(),
e03c0c1d 1381 'instanceid' => $instance->instance->id,
9b4b78fd 1382 'blockaction' => 'config'
1383 );
f032aa7a 1384
1385 // To this data, add anything the page itself needs to display
ad52c04f 1386 $hiddendata = $page->url->params($hiddendata);
9b4b78fd 1387
294ce987 1388 if ($data = data_submitted()) {
9b4b78fd 1389 $remove = array_keys($hiddendata);
1390 foreach($remove as $item) {
1391 unset($data->$item);
0f3fe4b6 1392 }
e03c0c1d 1393 $instance->instance_config_save($data);
1394 redirect($page->url->out());
1395
1396 } else {
f032aa7a 1397 // We need to show the config screen, so we highjack the display logic and then die
e82d6cac 1398 $strheading = get_string('blockconfiga', 'moodle', $blocktitle);
e03c0c1d 1399 $nav = build_navigation($strheading, $page->cm);
1400 print_header($strheading, $strheading, $nav);
b9709905 1401
e03c0c1d 1402 echo '<div class="block-config" id="'.$instance->name().'">'; /// Make CSS easier
0be6f678 1403
edb42f09 1404 print_heading($strheading);
ad52c04f 1405 echo '<form method="post" name="block-config" action="'. $page->url->out(false) .'">';
9b4b78fd 1406 echo '<p>';
e03c0c1d 1407 echo $page->url->hidden_params_out(array(), 0, $hiddendata);
9b4b78fd 1408 echo '</p>';
e03c0c1d 1409 $instance->instance_config_print();
9b4b78fd 1410 echo '</form>';
b9709905 1411
1412 echo '</div>';
e03c0c1d 1413 global $PAGE;
1414 $PAGE->set_docs_path('blocks/' . $instance->name());
9b4b78fd 1415 print_footer();
e03c0c1d 1416 die; // Do not go on with the other page-related stuff
0f3fe4b6 1417 }
1418 break;
9b4b78fd 1419 case 'toggle':
1420 if(empty($instance)) {
e49ef64a 1421 print_error('invalidblockinstance', '', '', $blockaction);
0f3fe4b6 1422 }
9b4b78fd 1423 $instance->visible = ($instance->visible) ? 0 : 1;
0d6b9d4f 1424 if (!empty($pinned)) {
66b10689 1425 $DB->update_record('block_pinned_old', $instance);
0d6b9d4f 1426 } else {
66b10689 1427 $DB->update_record('block_instance_old', $instance);
0d6b9d4f 1428 }
9b4b78fd 1429 break;
1430 case 'delete':
1431 if(empty($instance)) {
e49ef64a 1432 print_error('invalidblockinstance', '', '', $blockaction);
0f3fe4b6 1433 }
f4d38d20 1434 blocks_delete_instance($instance->instance, $pinned);
0f3fe4b6 1435 break;
1436 case 'moveup':
9b4b78fd 1437 if(empty($instance)) {
e49ef64a 1438 print_error('invalidblockinstance', '', '', $blockaction);
9b4b78fd 1439 }
f032aa7a 1440
1441 if($instance->weight == 0) {
1442 // The block is the first one, so a move "up" probably means it changes position
1443 // Where is the instance going to be moved?
1444 $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_UP);
bb46a4fa 1445 $newweight = (empty($blockmanager[$newpos]) ? 0 : max(array_keys($blockmanager[$newpos])) + 1);
f032aa7a 1446
0d6b9d4f 1447 blocks_execute_repositioning($instance, $newpos, $newweight, $pinned);
89a5baab 1448 }
f032aa7a 1449 else {
1450 // The block is just moving upwards in the same position.
1451 // This configuration will make sure that even if somehow the weights
1452 // become not continuous, block move operations will eventually bring
1453 // the situation back to normal without printing any warnings.
bb46a4fa 1454 if(!empty($blockmanager[$instance->position][$instance->weight - 1])) {
1455 $other = $blockmanager[$instance->position][$instance->weight - 1];
f032aa7a 1456 }
1457 if(!empty($other)) {
1458 ++$other->weight;
0d6b9d4f 1459 if (!empty($pinned)) {
66b10689 1460 $DB->update_record('block_pinned_old', $other);
0d6b9d4f 1461 } else {
66b10689 1462 $DB->update_record('block_instance_old', $other);
afd1ec02 1463 }
f032aa7a 1464 }
1465 --$instance->weight;
0d6b9d4f 1466 if (!empty($pinned)) {
66b10689 1467 $DB->update_record('block_pinned_old', $instance);
0d6b9d4f 1468 } else {
66b10689 1469 $DB->update_record('block_instance_old', $instance);
0d6b9d4f 1470 }
0f3fe4b6 1471 }
1472 break;
1473 case 'movedown':
9b4b78fd 1474 if(empty($instance)) {
e49ef64a 1475 print_error('invalidblockinstance', '', '', $blockaction);
9b4b78fd 1476 }
f032aa7a 1477
bb46a4fa 1478 if($instance->weight == max(array_keys($blockmanager[$instance->position]))) {
f032aa7a 1479 // The block is the last one, so a move "down" probably means it changes position
1480 // Where is the instance going to be moved?
1481 $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_DOWN);
bb46a4fa 1482 $newweight = (empty($blockmanager[$newpos]) ? 0 : max(array_keys($blockmanager[$newpos])) + 1);
f032aa7a 1483
0d6b9d4f 1484 blocks_execute_repositioning($instance, $newpos, $newweight, $pinned);
89a5baab 1485 }
f032aa7a 1486 else {
1487 // The block is just moving downwards in the same position.
1488 // This configuration will make sure that even if somehow the weights
1489 // become not continuous, block move operations will eventually bring
1490 // the situation back to normal without printing any warnings.
bb46a4fa 1491 if(!empty($blockmanager[$instance->position][$instance->weight + 1])) {
1492 $other = $blockmanager[$instance->position][$instance->weight + 1];
f032aa7a 1493 }
1494 if(!empty($other)) {
1495 --$other->weight;
0d6b9d4f 1496 if (!empty($pinned)) {
66b10689 1497 $DB->update_record('block_pinned_old', $other);
0d6b9d4f 1498 } else {
66b10689 1499 $DB->update_record('block_instance_old', $other);
0d6b9d4f 1500 }
f032aa7a 1501 }
1502 ++$instance->weight;
0d6b9d4f 1503 if (!empty($pinned)) {
66b10689 1504 $DB->update_record('block_pinned_old', $instance);
0d6b9d4f 1505 } else {
66b10689 1506 $DB->update_record('block_instance_old', $instance);
0d6b9d4f 1507 }
0f3fe4b6 1508 }
1509 break;
9b4b78fd 1510 case 'moveleft':
1511 if(empty($instance)) {
e49ef64a 1512 print_error('invalidblockinstance', '', '', $blockaction);
9b4b78fd 1513 }
f032aa7a 1514
1515 // Where is the instance going to be moved?
1516 $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_LEFT);
bb46a4fa 1517 $newweight = (empty($blockmanager[$newpos]) ? 0 : max(array_keys($blockmanager[$newpos])) + 1);
f032aa7a 1518
0d6b9d4f 1519 blocks_execute_repositioning($instance, $newpos, $newweight, $pinned);
0f3fe4b6 1520 break;
9b4b78fd 1521 case 'moveright':
1522 if(empty($instance)) {
e49ef64a 1523 print_error('invalidblockinstance', '', '', $blockaction);
9b4b78fd 1524 }
f032aa7a 1525
1526 // Where is the instance going to be moved?
1527 $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_RIGHT);
bb46a4fa 1528 $newweight = (empty($blockmanager[$newpos]) ? 0 : max(array_keys($blockmanager[$newpos])) + 1);
f032aa7a 1529
0d6b9d4f 1530 blocks_execute_repositioning($instance, $newpos, $newweight, $pinned);
9b4b78fd 1531 break;
1532 case 'add':
1533 // Add a new instance of this block, if allowed
1534 $block = blocks_get_record($blockid);
0f3fe4b6 1535
feed1900 1536 if (empty($block) || !$block->visible) {
3cacefda 1537 // Only allow adding if the block exists and is enabled
11306331 1538 break;
9b4b78fd 1539 }
0f3fe4b6 1540
feed1900 1541 if (!$block->multiple && blocks_find_block($blockid, $blockmanager) !== false) {
89a5baab 1542 // If no multiples are allowed and we already have one, return now
11306331 1543 break;
1544 }
1545
feed1900 1546 if (!block_method_result($block->name, 'user_can_addto', $page)) {
11306331 1547 // If the block doesn't want to be added...
1548 break;
89a5baab 1549 }
1550
feed1900 1551 $region = $page->blocks->get_default_region();
7130fb21 1552 $weight = $DB->get_field_sql("SELECT MAX(defaultweight) FROM {block_instances}
13a0d3d3 1553 WHERE parentcontextid = ? AND defaultregion = ?", array($page->context->id, $region));
feed1900 1554 $pagetypepattern = $page->pagetype;
1555 if (strpos($pagetypepattern, 'course-view') === 0) {
1556 $pagetypepattern = 'course-view-*';
b33dd23a 1557 }
feed1900 1558 $page->blocks->add_block($block->name, $region, $weight, false, $pagetypepattern);
9b4b78fd 1559 break;
1560 }
f032aa7a 1561
b1631fef 1562 if ($redirect) {
1563 // In order to prevent accidental duplicate actions, redirect to a page with a clean url
ad52c04f 1564 redirect($page->url->out());
b1631fef 1565 }
f032aa7a 1566}
1567
d4accfc0 1568/**
d4a03c00 1569 * TODO deprecate
1570 *
d4accfc0 1571 * You can use this to get the blocks to respond to URL actions without much hassle
1572 *
d4accfc0 1573 * @param object $PAGE
1574 * @param object $blockmanager
1575 * @param bool $pinned
1576 */
bb46a4fa 1577function blocks_execute_url_action(&$PAGE, &$blockmanager,$pinned=false) {
02cc05a7 1578 $blockaction = optional_param('blockaction', '', PARAM_ALPHA);
da71112b 1579
3edc57e1 1580 if (empty($blockaction) || !$PAGE->user_allowed_editing() || !confirm_sesskey()) {
da71112b 1581 return;
1582 }
1583
1584 $instanceid = optional_param('instanceid', 0, PARAM_INT);
1585 $blockid = optional_param('blockid', 0, PARAM_INT);
afd1ec02 1586
da71112b 1587 if (!empty($blockid)) {
bb46a4fa 1588 blocks_execute_action($PAGE, $blockmanager, strtolower($blockaction), $blockid, $pinned);
f4d38d20 1589 } else if (!empty($instanceid)) {
1590 $instance = $blockmanager->find_instance($instanceid);
bb46a4fa 1591 blocks_execute_action($PAGE, $blockmanager, strtolower($blockaction), $instance, $pinned);
da71112b 1592 }
1593}
1594
d4accfc0 1595/**
d4a03c00 1596 * TODO deprecate
d4accfc0 1597 * This shouldn't be used externally at all, it's here for use by blocks_execute_action()
1598 * in order to reduce code repetition.
1599 *
1600 * @todo Remove exception when MDL-19010 is fixed
1601 *
1602 * global object
1603 * @param $instance
1604 * @param $newpos
1605 * @param string|int $newweight
1606 * @param bool $pinned
1607 */
29ca8b88 1608function blocks_execute_repositioning(&$instance, $newpos, $newweight, $pinned=false) {
58ff964f 1609 global $DB;
f032aa7a 1610
feed1900 1611 throw new moodle_exception('Sorry, blocks editing is currently broken. Will be fixed. See MDL-19010.');
1612
c4308cfa 1613 // If it's staying where it is, don't do anything, unless overridden
29ca8b88 1614 if ($newpos == $instance->position) {
f032aa7a 1615 return;
1616 }
1617
1618 // Close the weight gap we 'll leave behind
0d6b9d4f 1619 if (!empty($pinned)) {
66b10689 1620 $sql = "UPDATE {block_instance_old}
58ff964f 1621 SET weight = weight - 1
1622 WHERE pagetype = ? AND position = ? AND weight > ?";
1623 $params = array($instance->pagetype, $instance->position, $instance->weight);
1624
0d6b9d4f 1625 } else {
66b10689 1626 $sql = "UPDATE {block_instance_old}
58ff964f 1627 SET weight = weight - 1
1628 WHERE pagetype = ? AND pageid = ?
1629 AND position = ? AND weight > ?";
1630 $params = array($instance->pagetype, $instance->pageid, $instance->position, $instance->weight);
0d6b9d4f 1631 }
58ff964f 1632 $DB->execute($sql, $params);
f032aa7a 1633
1634 $instance->position = $newpos;
1635 $instance->weight = $newweight;
1636
0d6b9d4f 1637 if (!empty($pinned)) {
66b10689 1638 $DB->update_record('block_pinned_old', $instance);
0d6b9d4f 1639 } else {
66b10689 1640 $DB->update_record('block_instance_old', $instance);
0d6b9d4f 1641 }
1642}
1643
29ca8b88 1644
1645/**
d4a03c00 1646 * TODO deprecate
29ca8b88 1647 * Moves a block to the new position (column) and weight (sort order).
d4accfc0 1648 *
d4accfc0 1649 * @param object $instance The block instance to be moved.
1650 * @param string $destpos BLOCK_POS_LEFT or BLOCK_POS_RIGHT. The destination column.
1651 * @param string $destweight The destination sort order. If NULL, we add to the end
1652 * of the destination column.
1653 * @param bool $pinned Are we moving pinned blocks? We can only move pinned blocks
1654 * to a new position withing the pinned list. Likewise, we
1655 * can only moved non-pinned blocks to a new position within
1656 * the non-pinned list.
1657 * @return boolean success or failure
29ca8b88 1658 */
1659function blocks_move_block($page, &$instance, $destpos, $destweight=NULL, $pinned=false) {
58ff964f 1660 global $CFG, $DB;
afd1ec02 1661
feed1900 1662 throw new moodle_exception('Sorry, blocks editing is currently broken. Will be fixed. See MDL-19010.');
1663
29ca8b88 1664 if ($pinned) {
d4a03c00 1665 $blocklist = array(); //blocks_get_pinned($page);
29ca8b88 1666 } else {
d4a03c00 1667 $blocklist = array(); //blocks_get_by_page($page);
29ca8b88 1668 }
afd1ec02 1669
29ca8b88 1670 if ($blocklist[$instance->position][$instance->weight]->id != $instance->id) {
1671 // The source block instance is not where we think it is.
c4308cfa 1672 return false;
d23157d8 1673 }
afd1ec02 1674
29ca8b88 1675 // First we close the gap that will be left behind when we take out the
1676 // block from it's current column.
1677 if ($pinned) {
66b10689 1678 $closegapsql = "UPDATE {block_instance_old}
afd1ec02 1679 SET weight = weight - 1
58ff964f 1680 WHERE weight > ? AND position = ? AND pagetype = ?";
1681 $params = array($instance->weight, $instance->position, $instance->pagetype);
e028ed34 1682 } else {
66b10689 1683 $closegapsql = "UPDATE {block_instance_old}
afd1ec02 1684 SET weight = weight - 1
58ff964f 1685 WHERE weight > ? AND position = ?
1686 AND pagetype = ? AND pageid = ?";
1687 $params = array($instance->weight, $instance->position, $instance->pagetype, $instance->pageid);
29ca8b88 1688 }
58ff964f 1689 if (!$DB->execute($closegapsql, $params)) {
29ca8b88 1690 return false;
77e65ff7 1691 }
afd1ec02 1692
29ca8b88 1693 // Now let's make space for the block being moved.
1694 if ($pinned) {
66b10689 1695 $opengapsql = "UPDATE {block_instance_old}
afd1ec02 1696 SET weight = weight + 1
58ff964f 1697 WHERE weight >= ? AND position = ? AND pagetype = ?";
1698 $params = array($destweight, $destpos, $instance->pagetype);
d23157d8 1699 } else {
66b10689 1700 $opengapsql = "UPDATE {block_instance_old}
58ff964f 1701 SET weight = weight + 1
1702 WHERE weight >= ? AND position = ?
1703 AND pagetype = ? AND pageid = ?";
1704 $params = array($destweight, $destpos, $instance->pagetype, $instance->pageid);
29ca8b88 1705 }
655b09ca 1706 if (!$DB->execute($opengapsql, $params)) {
29ca8b88 1707 return false;
c4308cfa 1708 }
afd1ec02 1709
29ca8b88 1710 // Move the block.
1711 $instance->position = $destpos;
1712 $instance->weight = $destweight;
e028ed34 1713
29ca8b88 1714 if ($pinned) {
66b10689 1715 $table = 'block_pinned_old';
29ca8b88 1716 } else {
66b10689 1717 $table = 'block_instance_old';
29ca8b88 1718 }
58ff964f 1719 return $DB->update_record($table, $instance);
e028ed34 1720}
1721
d4a03c00 1722// Functions for programatically adding default blocks to pages ================
0f3fe4b6 1723
9d1d606e 1724/**
1725 * Parse a list of default blocks. See config-dist for a description of the format.
d4accfc0 1726 *
9d1d606e 1727 * @param string $blocksstr
1728 * @return array
1729 */
1730function blocks_parse_default_blocks_list($blocksstr) {
f474a4e5 1731 $blocks = array();
1732 $bits = explode(':', $blocksstr);
1733 if (!empty($bits)) {
1734 $blocks[BLOCK_POS_LEFT] = explode(',', array_shift($bits));
1735 }
1736 if (!empty($bits)) {
1737 $blocks[BLOCK_POS_RIGHT] = explode(',', array_shift($bits));
1738 }
1739 return $blocks;
9d1d606e 1740}
5b224948 1741
9d1d606e 1742/**
1743 * @return array the blocks that should be added to the site course by default.
1744 */
1745function blocks_get_default_site_course_blocks() {
1746 global $CFG;
9b4b78fd 1747
9d1d606e 1748 if (!empty($CFG->defaultblocks_site)) {
f474a4e5 1749 return blocks_parse_default_blocks_list($CFG->defaultblocks_site);
9d1d606e 1750 } else {
f474a4e5 1751 return array(
9d1d606e 1752 BLOCK_POS_LEFT => array('site_main_menu', 'admin_tree'),
1753 BLOCK_POS_RIGHT => array('course_summary', 'calendar_month')
1754 );
9b4b78fd 1755 }
9d1d606e 1756}
1757
1758/**
1759 * Add the default blocks to a course.
d4accfc0 1760 *
9d1d606e 1761 * @param object $course a course object.
1762 */
1763function blocks_add_default_course_blocks($course) {
1764 global $CFG;
1765
1766 if (!empty($CFG->defaultblocks_override)) {
1767 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks_override);
1768
1769 } else if ($course->id == SITEID) {
1770 $blocknames = blocks_get_default_site_course_blocks();
1771
1772 } else {
1773 $defaultblocks = 'defaultblocks_' . $course->format;
1774 if (!empty($CFG->$defaultblocks)) {
1775 $blocknames = blocks_parse_default_blocks_list($CFG->$defaultblocks);
1776
1777 } else {
1d00ec6a 1778 $formatconfig = $CFG->dirroot.'/course/format/'.$course->format.'/config.php';
1779 if (is_readable($formatconfig)) {
9d1d606e 1780 require($formatconfig);
1781 }
1782 if (!empty($format['defaultblocks'])) {
1783 $blocknames = blocks_parse_default_blocks_list($format['defaultblocks']);
9b4b78fd 1784
9d1d606e 1785 } else if (!empty($CFG->defaultblocks)){
1786 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks);
1787
1788 } else {
1789 $blocknames = array(
1790 BLOCK_POS_LEFT => array('participants', 'activity_modules', 'search_forums', 'admin', 'course_list'),
1791 BLOCK_POS_RIGHT => array('news_items', 'calendar_upcoming', 'recent_activity')
1792 );
1793 }
1794 }
9b4b78fd 1795 }
1796
f474a4e5 1797 if ($course->id == SITEID) {
1798 $pagetypepattern = 'site-index';
1799 } else {
1800 $pagetypepattern = 'course-view-*';
1801 }
1802
9d1d606e 1803 $page = new moodle_page();
1804 $page->set_course($course);
f474a4e5 1805 $page->blocks->add_blocks($blocknames, $pagetypepattern);
9d1d606e 1806}
1807
1808/**
1809 * Add the default system-context blocks. E.g. the admin tree.
1810 */
1811function blocks_add_default_system_blocks() {
1812 $page = new moodle_page();
1813 $page->set_context(get_context_instance(CONTEXT_SYSTEM));
1814 $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_tree', 'admin_bookmarks')), 'admin-*');
1815}