dcb1bd3c |
1 | <?php //$Id$ |
0f3fe4b6 |
2 | |
e8c8cee9 |
3 | /////////////////////////////////////////////////////////////////////////// |
4 | // // |
5 | // NOTICE OF COPYRIGHT // |
6 | // // |
7 | // Moodle - Modular Object-Oriented Dynamic Learning Environment // |
8 | // http://moodle.org // |
9 | // // |
10 | // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com // |
11 | // // |
12 | // This program is free software; you can redistribute it and/or modify // |
13 | // it under the terms of the GNU General Public License as published by // |
14 | // the Free Software Foundation; either version 2 of the License, or // |
15 | // (at your option) any later version. // |
16 | // // |
17 | // This program is distributed in the hope that it will be useful, // |
18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of // |
19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // |
20 | // GNU General Public License for more details: // |
21 | // // |
22 | // http://www.gnu.org/copyleft/gpl.html // |
23 | // // |
24 | /////////////////////////////////////////////////////////////////////////// |
25 | |
26 | /** |
27 | * This library includes all the necessary stuff to use blocks on pages in Moodle. |
28 | * |
29 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
30 | * @package pages |
31 | */ |
0f3fe4b6 |
32 | |
0f3fe4b6 |
33 | define('BLOCK_MOVE_LEFT', 0x01); |
34 | define('BLOCK_MOVE_RIGHT', 0x02); |
35 | define('BLOCK_MOVE_UP', 0x04); |
36 | define('BLOCK_MOVE_DOWN', 0x08); |
9b4b78fd |
37 | define('BLOCK_CONFIGURE', 0x10); |
0f3fe4b6 |
38 | |
9b4b78fd |
39 | define('BLOCK_POS_LEFT', 'l'); |
40 | define('BLOCK_POS_RIGHT', 'r'); |
0e9af917 |
41 | |
ee6055eb |
42 | define('BLOCKS_PINNED_TRUE',0); |
43 | define('BLOCKS_PINNED_FALSE',1); |
44 | define('BLOCKS_PINNED_BOTH',2); |
45 | |
f032aa7a |
46 | require_once($CFG->libdir.'/pagelib.php'); |
61abc65b |
47 | |
86b5ea0f |
48 | /** |
49 | * This class keeps track of the block that should appear on a moodle_page. |
50 | * The page to work with as passed to the constructor. |
51 | * The only fields of moodle_page that is uses are ->context, ->pagetype and |
52 | * ->subpage, so instead of passing a full moodle_page object, you may also |
53 | * pass a stdClass object with those three fields. These field values are read |
54 | * only at the point that the load_blocks() method is called. It is the caller's |
55 | * responsibility to ensure that those fields do not subsequently change. |
56 | */ |
57 | class block_manager { |
86b5ea0f |
58 | |
59 | /// Field declarations ========================================================= |
60 | |
86b5ea0f |
61 | protected $page; |
62 | |
63 | protected $regions = array(); |
64 | |
65 | protected $defaultregion; |
66 | |
08eab897 |
67 | protected $allblocks = null; // Will be get_records('blocks'); |
68 | |
69 | protected $addableblocks = null; // Will be a subset of $allblocks. |
70 | |
71 | protected $blocksbyregion = null; // Will be an array region-name => array(block_instances); |
72 | |
86b5ea0f |
73 | /// Constructor ================================================================ |
74 | |
75 | /** |
76 | * Constructor. |
77 | * @param object $page the moodle_page object object we are managing the blocks for, |
78 | * or a reasonable faxilimily. (See the comment at the top of this classe |
79 | * and http://en.wikipedia.org/wiki/Duck_typing) |
80 | */ |
81 | public function __construct($page) { |
82 | $this->page = $page; |
83 | } |
84 | |
85 | /// Getter methods ============================================================= |
86 | |
87 | /** |
88 | * @return array the internal names of the regions on this page where block may appear. |
89 | */ |
90 | public function get_regions() { |
91 | return array_keys($this->regions); |
92 | } |
93 | |
94 | /** |
95 | * @return string the internal names of the region where new blocks are added |
96 | * by default, and where any blocks from an unrecognised region are shown. |
97 | * (Imagine that blocks were added with one theme selected, then you switched |
98 | * to a theme with different block positions.) |
99 | */ |
100 | public function get_default_region() { |
101 | return $this->defaultregion; |
102 | } |
103 | |
08eab897 |
104 | /** |
105 | * The list of block types that may be added to this page. |
106 | * @return array block id => record from block table. |
107 | */ |
108 | public function get_addable_blocks() { |
109 | $this->check_is_loaded(); |
110 | |
111 | if (!is_null($this->addableblocks)) { |
112 | return $this->addableblocks; |
113 | } |
114 | |
115 | // Lazy load. |
116 | $this->addableblocks = array(); |
117 | |
118 | $allblocks = blocks_get_record(); |
119 | if (empty($allblocks)) { |
120 | return $this->addableblocks; |
121 | } |
122 | |
123 | $pageformat = $page->pagetype; |
124 | foreach($allblocks as $block) { |
125 | if ($block->visible && |
126 | ($block->multiple || !$this->is_block_present($block->id)) && |
127 | blocks_name_allowed_in_format($block->name, $pageformat)) { |
128 | $this->addableblocks[$block->id] = $block; |
129 | } |
130 | } |
131 | |
132 | return $this->addableblocks; |
133 | } |
134 | |
135 | public function is_block_present($blocktypeid) { |
136 | // TODO |
137 | } |
138 | |
139 | /** |
140 | * @param string $blockname the name of ta type of block. |
141 | * @param boolean $includeinvisible if false (default) only check 'visible' blocks, that is, blocks enabled by the admin. |
142 | * @return boolean true if this block in installed. |
143 | */ |
144 | public function is_known_block_type($blockname, $includeinvisible = false) { |
145 | $blocks = $this->get_installed_blocks(); |
146 | foreach ($blocks as $block) { |
147 | if ($block->name == $blockname && ($includeinvisible || $block->visible)) { |
148 | return true; |
149 | } |
150 | } |
151 | return false; |
152 | } |
153 | |
154 | /** |
155 | * @param string $region a region name |
156 | * @return boolean true if this retion exists on this page. |
157 | */ |
158 | public function is_known_region($region) { |
159 | return array_key_exists($region, $this->regions); |
160 | } |
161 | |
162 | /** |
163 | * @param $region a block region that exists on this page. |
164 | * @return array of block instances. |
165 | */ |
166 | public function get_blocks_for_region($region) { |
167 | $this->check_is_loaded(); |
168 | $this->check_region_is_known($region); |
169 | return $this->blocksbyregion[$region]; |
170 | } |
171 | |
172 | /** |
173 | * Get the list of all installed blocks. |
174 | * @return array contents of the block table. |
175 | */ |
176 | public function get_installed_blocks() { |
177 | global $DB; |
178 | if (is_null($this->allblocks)) { |
179 | $this->allblocks = $DB->get_records('block'); |
180 | } |
181 | return $this->allblocks; |
182 | } |
183 | |
86b5ea0f |
184 | /// Setter methods ============================================================= |
185 | |
186 | /** |
187 | * @param string $region add a named region where blocks may appear on the |
188 | * current page. This is an internal name, like 'side-pre', not a string to |
189 | * display in the UI. |
190 | */ |
191 | public function add_region($region) { |
192 | $this->check_not_yet_loaded(); |
193 | $this->regions[$region] = 1; |
194 | } |
195 | |
196 | /** |
197 | * @param array $regions this utility method calls add_region for each array element. |
198 | */ |
199 | public function add_regions($regions) { |
200 | foreach ($regions as $region) { |
201 | $this->add_region($region); |
202 | } |
203 | } |
204 | |
205 | /** |
206 | * @param string $defaultregion the internal names of the region where new |
207 | * blocks should be added by default, and where any blocks from an |
208 | * unrecognised region are shown. |
209 | */ |
210 | public function set_default_region($defaultregion) { |
211 | $this->check_not_yet_loaded(); |
08eab897 |
212 | $this->check_region_is_known($defaultregion); |
86b5ea0f |
213 | $this->defaultregion = $defaultregion; |
214 | } |
215 | |
08eab897 |
216 | /// Actions ==================================================================== |
217 | |
218 | /** |
219 | * This method actually loads the blocks for our page from the database. |
220 | */ |
221 | public function load_blocks($includeinvisible = NULL) { |
222 | global $DB; |
223 | $this->check_not_yet_loaded(); |
224 | |
225 | if (is_null($includeinvisible)) { |
226 | $includeinvisible = $this->page->user_is_editing(); |
227 | } |
228 | if ($includeinvisible) { |
229 | $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; |
230 | } else { |
231 | $visiblecheck = ''; |
232 | } |
233 | |
234 | $context = $this->page->context; |
235 | $contexttest = 'bi.contextid = :contextid2'; |
236 | $parentcontextparams = array(); |
237 | $parentcontextids = get_parent_contexts($context); |
238 | if ($parentcontextids) { |
239 | list($parentcontexttest, $parentcontextparams) = |
240 | $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000'); |
241 | $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.contextid $parentcontexttest))"; |
242 | } |
243 | |
244 | $pagetypepatterns = $this->matching_page_type_patterns($this->page->pagetype); |
245 | list($pagetypepatterntest, $pagetypepatternparams) = |
246 | $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000'); |
247 | |
248 | $params = array( |
249 | 'subpage1' => $this->page->subpage, |
250 | 'subpage2' => $this->page->subpage, |
251 | 'contextid1' => $context->id, |
252 | 'contextid2' => $context->id, |
253 | 'pagetype' => $this->page->pagetype, |
254 | ); |
255 | $sql = "SELECT |
256 | bi.id, |
257 | bi.blockname, |
258 | bi.contextid, |
259 | bi.showinsubcontexts, |
260 | bi.pagetypepattern, |
261 | bi.subpagepattern, |
262 | bp.visible, |
263 | COALESCE(bp.region, bi.defaultregion) AS region, |
264 | COALESCE(bp.weight, bi.defaultweight) AS weight, |
265 | bi.configdata |
266 | |
267 | FROM {block_instances} bi |
268 | JOIN {block} b ON bi.blockname = b.name |
269 | LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id |
270 | AND bp.contextid = :contextid1 |
271 | AND bp.pagetype = :pagetype |
272 | AND bp.subpage = :subpage1 |
273 | |
274 | WHERE |
275 | $contexttest |
276 | AND bi.pagetypepattern $pagetypepatterntest |
277 | AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2) |
278 | $visiblecheck |
279 | AND b.visible = 1 |
280 | |
281 | ORDER BY |
282 | COALESCE(bp.region, bi.defaultregion), |
283 | COALESCE(bp.weight, bi.defaultweight), |
284 | bi.id"; |
285 | $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); |
286 | |
287 | $this->blocksbyregion = array(); |
288 | foreach ($this->regions as $region => $notused) { |
289 | $this->blocksbyregion[$region] = array(); |
290 | } |
291 | $unknown = array(); |
292 | |
293 | foreach ($blockinstances as $bi) { |
294 | if ($this->is_known_region($bi->region)) { |
295 | $this->blocksbyregion[$bi->region][] = $bi; |
296 | } else { |
297 | $unknown[] = $bi; |
298 | } |
299 | } |
300 | $this->blocksbyregion[$this->defaultregion] = array_merge($this->blocksbyregion[$this->defaultregion], $unknown); |
301 | } |
302 | |
303 | /** |
304 | * Add a block to the current page, or related pages. The block is added to |
305 | * context $this->page->contextid. If $pagetypepattern $subpagepattern |
306 | * @param string $blockname The type of block to add. |
307 | * @param string $region the block region on this page to add the block to. |
308 | * @param integer $weight determines the order where this block appears in the region. |
309 | * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context. |
310 | * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type. |
311 | * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage. |
312 | */ |
313 | public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) { |
314 | global $DB; |
315 | $this->check_known_block_type($blockname); |
316 | $this->check_region_is_known($region); |
317 | |
318 | if (empty($pagetypepattern)) { |
319 | $pagetypepattern = $this->page->pagetype; |
320 | } |
321 | |
322 | $blockinstance = new stdClass; |
323 | $blockinstance->blockname = $blockname; |
324 | $blockinstance->contextid = $this->page->context->id; |
325 | $blockinstance->showinsubcontexts = !empty($showinsubcontexts); |
326 | $blockinstance->pagetypepattern = $pagetypepattern; |
327 | $blockinstance->subpagepattern = $subpagepattern; |
328 | $blockinstance->defaultregion = $region; |
329 | $blockinstance->defaultweight = $weight; |
330 | $blockinstance->configdata = ''; |
331 | $DB->insert_record('block_instances', $blockinstance); |
332 | } |
333 | |
86b5ea0f |
334 | /// Inner workings ============================================================= |
335 | |
08eab897 |
336 | /** |
337 | * Given a specific page type, return all the page type patterns that might |
338 | * match it. |
339 | * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'. |
340 | * @return array an array of all the page type patterns that might match this page type. |
341 | */ |
342 | protected function matching_page_type_patterns($pagetype) { |
343 | $patterns = array($pagetype, '*'); |
344 | $bits = explode('-', $pagetype); |
345 | if (count($bits) == 3 && $bits[0] == 'mod') { |
346 | if ($bits[2] == 'view') { |
347 | $patterns[] = 'mod-*-view'; |
348 | } else if ($bits[2] == 'index') { |
349 | $patterns[] = 'mod-*-index'; |
350 | } |
351 | } |
352 | while (count($bits) > 0) { |
353 | $patterns[] = implode('-', $bits) . '-*'; |
354 | array_pop($bits); |
355 | } |
356 | return $patterns; |
357 | } |
358 | |
86b5ea0f |
359 | protected function check_not_yet_loaded() { |
08eab897 |
360 | if (!is_null($this->blocksbyregion)) { |
86b5ea0f |
361 | 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.'); |
362 | } |
363 | } |
364 | |
08eab897 |
365 | protected function check_is_loaded() { |
366 | if (is_null($this->blocksbyregion)) { |
367 | throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.'); |
368 | } |
369 | } |
370 | |
371 | protected function check_known_block_type($blockname, $includeinvisible = false) { |
372 | if (!$this->is_known_block_type($blockname, $includeinvisible)) { |
373 | if ($this->is_known_block_type($blockname, true)) { |
374 | throw new coding_exception('Unknown block type ' . $blockname); |
375 | } else { |
376 | throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.'); |
377 | } |
378 | } |
379 | } |
380 | |
381 | protected function check_region_is_known($region) { |
382 | if (!$this->is_known_region($region)) { |
383 | throw new coding_exception('Trying to reference an unknown block region ' . $region); |
384 | } |
86b5ea0f |
385 | } |
386 | } |
387 | |
08eab897 |
388 | /// Helper functions for working with block classes ============================ |
389 | |
390 | /** |
391 | * Call a class method (one that does not requrie a block instance) on a block class. |
392 | * @param string $blockname the name of the block. |
393 | * @param string $method the method name. |
394 | * @param array $param parameters to pass to the method. |
395 | * @return mixed whatever the method returns. |
396 | */ |
11306331 |
397 | function block_method_result($blockname, $method, $param = NULL) { |
0f3fe4b6 |
398 | if(!block_load_class($blockname)) { |
399 | return NULL; |
400 | } |
11306331 |
401 | return call_user_func(array('block_'.$blockname, $method), $param); |
0f3fe4b6 |
402 | } |
403 | |
08eab897 |
404 | /** |
405 | * Creates a new object of the specified block class. |
406 | * @param string $blockname the name of the block. |
407 | * @param $instance block_instances DB table row (optional). |
408 | * @return block_base the requested block instance. |
409 | */ |
9b4b78fd |
410 | function block_instance($blockname, $instance = NULL) { |
0f3fe4b6 |
411 | if(!block_load_class($blockname)) { |
412 | return false; |
413 | } |
e89d741a |
414 | $classname = 'block_'.$blockname; |
f032aa7a |
415 | $retval = new $classname; |
9b4b78fd |
416 | if($instance !== NULL) { |
1345403a |
417 | $retval->_load_instance($instance); |
9b4b78fd |
418 | } |
419 | return $retval; |
0f3fe4b6 |
420 | } |
421 | |
08eab897 |
422 | /** |
423 | * Load the block class for a particular type of block. |
424 | * @param string $blockname the name of the block. |
425 | * @return boolean success or failure. |
426 | */ |
0f3fe4b6 |
427 | function block_load_class($blockname) { |
428 | global $CFG; |
429 | |
a9033ad5 |
430 | if(empty($blockname)) { |
c7a9e293 |
431 | return false; |
432 | } |
433 | |
e89d741a |
434 | $classname = 'block_'.$blockname; |
a9033ad5 |
435 | |
436 | if(class_exists($classname)) { |
437 | return true; |
438 | } |
439 | |
440 | require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); |
e9a20759 |
441 | @include_once($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'); // do not throw errors if block code not present |
0f3fe4b6 |
442 | |
0f3fe4b6 |
443 | return class_exists($classname); |
444 | } |
445 | |
08eab897 |
446 | /// Functions that have been deprecated by block_manager ======================= |
f032aa7a |
447 | |
08eab897 |
448 | /** |
449 | * @deprecated since Moodle 2.0 - use $page->blocks->get |
450 | * This function returns an array with the IDs of any blocks that you can add to your page. |
451 | * Parameters are passed by reference for speed; they are not modified at all. |
452 | * @param $page the page object. |
453 | * @param $pageblocks Not used. |
454 | * @return array of block type ids. |
455 | */ |
456 | function blocks_get_missing(&$page, &$pageblocks) { |
457 | return array_keys($page->blocks->get_addable_blocks()); |
f032aa7a |
458 | } |
459 | |
460 | function blocks_remove_inappropriate($page) { |
461 | $pageblocks = blocks_get_by_page($page); |
462 | |
463 | if(empty($pageblocks)) { |
464 | return; |
465 | } |
466 | |
d529807a |
467 | if(($pageformat = $page->pagetype) == NULL) { |
f032aa7a |
468 | return; |
469 | } |
470 | |
471 | foreach($pageblocks as $position) { |
472 | foreach($position as $instance) { |
473 | $block = blocks_get_record($instance->blockid); |
5bbbe0be |
474 | if(!blocks_name_allowed_in_format($block->name, $pageformat)) { |
8a47e075 |
475 | blocks_delete_instance($instance); |
f032aa7a |
476 | } |
477 | } |
478 | } |
479 | } |
480 | |
5bbbe0be |
481 | function blocks_name_allowed_in_format($name, $pageformat) { |
cd2bc3c9 |
482 | $accept = NULL; |
483 | $maxdepth = -1; |
484 | $formats = block_method_result($name, 'applicable_formats'); |
485 | if (!$formats) { |
486 | $formats = array(); |
487 | } |
488 | foreach ($formats as $format => $allowed) { |
489 | $formatregex = '/^'.str_replace('*', '[^-]*', $format).'.*$/'; |
490 | $depth = substr_count($format, '-'); |
491 | if (preg_match($formatregex, $pageformat) && $depth > $maxdepth) { |
492 | $maxdepth = $depth; |
493 | $accept = $allowed; |
5bbbe0be |
494 | } |
495 | } |
cd2bc3c9 |
496 | if ($accept === NULL) { |
5bbbe0be |
497 | $accept = !empty($formats['all']); |
498 | } |
499 | return $accept; |
500 | } |
501 | |
0d6b9d4f |
502 | function blocks_delete_instance($instance,$pinned=false) { |
58ff964f |
503 | global $DB; |
f032aa7a |
504 | |
e9a20759 |
505 | // Get the block object and call instance_delete() if possible |
7fa944ca |
506 | if($record = blocks_get_record($instance->blockid)) { |
507 | if($obj = block_instance($record->name, $instance)) { |
e9a20759 |
508 | // Return value ignored |
509 | $obj->instance_delete(); |
510 | } |
b33dd23a |
511 | } |
512 | |
0d6b9d4f |
513 | if (!empty($pinned)) { |
66b10689 |
514 | $DB->delete_records('block_pinned_old', array('id'=>$instance->id)); |
0d6b9d4f |
515 | // And now, decrement the weight of all blocks after this one |
66b10689 |
516 | $sql = "UPDATE {block_pinned_old} |
58ff964f |
517 | SET weight = weight - 1 |
518 | WHERE pagetype = ? AND position = ? AND weight > ?"; |
519 | $params = array($instance->pagetype, $instance->position, $instance->weight); |
520 | $DB->execute($sql, $params); |
0d6b9d4f |
521 | } else { |
522 | // Now kill the db record; |
66b10689 |
523 | $DB->delete_records('block_instance_old', array('oldid'=>$instance->id)); |
19f5b2db |
524 | delete_context(CONTEXT_BLOCK, $instance->id); |
0d6b9d4f |
525 | // And now, decrement the weight of all blocks after this one |
66b10689 |
526 | $sql = "UPDATE {block_instance_old} |
58ff964f |
527 | SET weight = weight - 1 |
528 | WHERE pagetype = ? AND pageid = ? |
529 | AND position = ? AND weight > ?"; |
530 | $params = array($instance->pagetype, $instance->pageid, $instance->position, $instance->weight); |
531 | $DB->execute($sql, $params); |
0d6b9d4f |
532 | } |
2e477369 |
533 | return true; |
f032aa7a |
534 | } |
535 | |
c8e0b579 |
536 | // Accepts an array of block instances and checks to see if any of them have content to display |
537 | // (causing them to calculate their content in the process). Returns true or false. Parameter passed |
538 | // by reference for speed; the array is actually not modified. |
dffd4bb9 |
539 | function blocks_have_content(&$pageblocks, $position) { |
0d6b9d4f |
540 | |
541 | if (empty($pageblocks) || !is_array($pageblocks) || !array_key_exists($position,$pageblocks)) { |
542 | return false; |
543 | } |
66c7e47b |
544 | // use a for() loop to get references to the array elements |
545 | // foreach() cannot fetch references in PHP v4.x |
546 | for ($n=0; $n<count($pageblocks[$position]);$n++) { |
547 | $instance = &$pageblocks[$position][$n]; |
6b726eb4 |
548 | if (empty($instance->visible)) { |
7933cc6b |
549 | continue; |
550 | } |
3ef642d9 |
551 | if(!$record = blocks_get_record($instance->blockid)) { |
7933cc6b |
552 | continue; |
553 | } |
3ef642d9 |
554 | if(!$obj = block_instance($record->name, $instance)) { |
9b4b78fd |
555 | continue; |
556 | } |
3ef642d9 |
557 | if(!$obj->is_empty()) { |
afd1ec02 |
558 | // cache rec and obj |
66c7e47b |
559 | // for blocks_print_group() |
b1a308be |
560 | $instance->rec = $record; |
afd1ec02 |
561 | $instance->obj = $obj; |
3ef642d9 |
562 | return true; |
0f3fe4b6 |
563 | } |
564 | } |
9b4b78fd |
565 | |
0f3fe4b6 |
566 | return false; |
567 | } |
568 | |
c8e0b579 |
569 | // This function prints one group of blocks in a page |
570 | // Parameters passed by reference for speed; they are not modified. |
66492322 |
571 | function blocks_print_group(&$page, &$pageblocks, $position) { |
6ad71d66 |
572 | global $COURSE, $CFG, $USER; |
66492322 |
573 | |
6b726eb4 |
574 | if (empty($pageblocks[$position])) { |
575 | $groupblocks = array(); |
b35fc182 |
576 | $maxweight = 0; |
6b726eb4 |
577 | } else { |
578 | $groupblocks = $pageblocks[$position]; |
579 | $maxweight = max(array_keys($groupblocks)); |
9b4b78fd |
580 | } |
3cdc4597 |
581 | |
6b726eb4 |
582 | |
583 | foreach ($groupblocks as $instance) { |
4374ee2c |
584 | if (!empty($instance->pinned)) { |
585 | $maxweight--; |
586 | } |
587 | } |
0f3fe4b6 |
588 | |
f032aa7a |
589 | $isediting = $page->user_is_editing(); |
6b726eb4 |
590 | |
591 | |
592 | foreach($groupblocks as $instance) { |
593 | |
afd1ec02 |
594 | |
66c7e47b |
595 | // $instance may have ->rec and ->obj |
596 | // cached from when we walked $pageblocks |
597 | // in blocks_have_content() |
598 | if (empty($instance->rec)) { |
6b726eb4 |
599 | if (empty($instance->blockid)) { |
600 | continue; // Can't do anything |
601 | } |
66c7e47b |
602 | $block = blocks_get_record($instance->blockid); |
603 | } else { |
604 | $block = $instance->rec; |
605 | } |
f809df70 |
606 | |
607 | if (empty($block)) { |
608 | // Block doesn't exist! We should delete this instance! |
609 | continue; |
610 | } |
611 | |
6b726eb4 |
612 | if (empty($block->visible)) { |
9b4b78fd |
613 | // Disabled by the admin |
614 | continue; |
615 | } |
afd1ec02 |
616 | |
66c7e47b |
617 | if (empty($instance->obj)) { |
618 | if (!$obj = block_instance($block->name, $instance)) { |
619 | // Invalid block |
620 | continue; |
621 | } |
622 | } else { |
623 | $obj = $instance->obj; |
ab0e4dd4 |
624 | } |
0f3fe4b6 |
625 | |
d7f688d4 |
626 | $editalways = false; |
0d6b9d4f |
627 | |
6b726eb4 |
628 | |
0d6b9d4f |
629 | if (($isediting && empty($instance->pinned)) || !empty($editalways)) { |
9b4b78fd |
630 | $options = 0; |
f032aa7a |
631 | // 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: |
632 | // the first block might still be able to move up if the page says so (i.e., it will change position) |
633 | $options |= BLOCK_MOVE_UP * ($instance->weight != 0 || ($page->blocks_move_position($instance, BLOCK_MOVE_UP) != $instance->position)); |
634 | // Same thing for downward movement |
635 | $options |= BLOCK_MOVE_DOWN * ($instance->weight != $maxweight || ($page->blocks_move_position($instance, BLOCK_MOVE_DOWN) != $instance->position)); |
636 | // For left and right movements, it's up to the page to tell us whether they are allowed |
637 | $options |= BLOCK_MOVE_RIGHT * ($page->blocks_move_position($instance, BLOCK_MOVE_RIGHT) != $instance->position); |
638 | $options |= BLOCK_MOVE_LEFT * ($page->blocks_move_position($instance, BLOCK_MOVE_LEFT ) != $instance->position); |
639 | // Finally, the block can be configured if the block class either allows multiple instances, or if it specifically |
640 | // allows instance configuration (multiple instances override that one). It doesn't have anything to do with what the |
641 | // administrator has allowed for this block in the site admin options. |
642 | $options |= BLOCK_CONFIGURE * ( $obj->instance_allow_multiple() || $obj->instance_allow_config() ); |
1345403a |
643 | $obj->_add_edit_controls($options); |
9b4b78fd |
644 | } |
0f3fe4b6 |
645 | |
0a0bb380 |
646 | if (!$instance->visible && empty($COURSE->javascriptportal)) { |
647 | if ($isediting) { |
1345403a |
648 | $obj->_print_shadow(); |
0f3fe4b6 |
649 | } |
0a0bb380 |
650 | } else { |
4a1a14c9 |
651 | global $COURSE; |
d23157d8 |
652 | if(!empty($COURSE->javascriptportal)) { |
653 | $COURSE->javascriptportal->currentblocksection = $position; |
654 | } |
1345403a |
655 | $obj->_print_block(); |
9b4b78fd |
656 | } |
d23157d8 |
657 | if (!empty($COURSE->javascriptportal) |
658 | && (empty($instance->pinned) || !$instance->pinned)) { |
afd1ec02 |
659 | $COURSE->javascriptportal->block_add('inst'.$instance->id, !$instance->visible); |
d23157d8 |
660 | } |
661 | } // End foreach |
662 | |
282c1695 |
663 | // Check if |
664 | // we are on the default position/side AND |
665 | // we're editing the page AND |
666 | // ( |
667 | // we have the capability to manage blocks OR |
668 | // we are in myMoodle page AND have the capibility to manage myMoodle blocks |
669 | // ) |
6ad71d66 |
670 | |
671 | // for constant PAGE_MY_MOODLE |
672 | include_once($CFG->dirroot.'/my/pagelib.php'); |
afd1ec02 |
673 | |
6ad71d66 |
674 | $coursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id); |
d529807a |
675 | $myownblogpage = (isset($page->filtertype) && isset($page->filterselect) && $page->pagetype=='blog-view' && $page->filtertype=='user' && $page->filterselect == $USER->id); |
afd1ec02 |
676 | |
6ad71d66 |
677 | $managecourseblocks = has_capability('moodle/site:manageblocks', $coursecontext); |
d529807a |
678 | $editmymoodle = $page->pagetype == PAGE_MY_MOODLE && has_capability('moodle/my:manageblocks', $coursecontext); |
afd1ec02 |
679 | |
86b5ea0f |
680 | if ($page->blocks->get_default_region() == $position && |
0be6f678 |
681 | $page->user_is_editing() && |
ee1efe0b |
682 | ($managecourseblocks || $editmymoodle || $myownblogpage || defined('ADMIN_STICKYBLOCKS'))) { |
6ad71d66 |
683 | |
66492322 |
684 | blocks_print_adminblock($page, $pageblocks); |
685 | } |
0f3fe4b6 |
686 | } |
687 | |
c8e0b579 |
688 | // This iterates over an array of blocks and calculates the preferred width |
689 | // Parameter passed by reference for speed; it's not modified. |
690 | function blocks_preferred_width(&$instances) { |
0f3fe4b6 |
691 | $width = 0; |
692 | |
9b4b78fd |
693 | if(empty($instances) || !is_array($instances)) { |
0f3fe4b6 |
694 | return 0; |
695 | } |
ff6191b7 |
696 | |
697 | $blocks = blocks_get_record(); |
698 | |
9b4b78fd |
699 | foreach($instances as $instance) { |
700 | if(!$instance->visible) { |
fe78a3dc |
701 | continue; |
0c9c6363 |
702 | } |
ff6191b7 |
703 | |
f809df70 |
704 | if (!array_key_exists($instance->blockid, $blocks)) { |
705 | // Block doesn't exist! We should delete this instance! |
706 | continue; |
707 | } |
708 | |
ff6191b7 |
709 | if(!$blocks[$instance->blockid]->visible) { |
9b687320 |
710 | continue; |
711 | } |
ff6191b7 |
712 | $pref = block_method_result($blocks[$instance->blockid]->name, 'preferred_width'); |
9b4b78fd |
713 | if($pref === NULL) { |
714 | continue; |
715 | } |
716 | if($pref > $width) { |
717 | $width = $pref; |
0f3fe4b6 |
718 | } |
719 | } |
720 | return $width; |
721 | } |
722 | |
08eab897 |
723 | /** |
724 | * Get the block record for a particulr blockid. |
725 | * @param $blockid block type id. If null, an array of all block types is returned. |
726 | * @param $notusedanymore No longer used. |
727 | * @return array|object row from block table, or all rows. |
728 | */ |
729 | function blocks_get_record($blockid = NULL, $notusedanymore = false) { |
730 | global $PAGE; |
731 | $blocks = $PAGE->blocks->get_installed_blocks(); |
732 | if ($blockid === NULL) { |
733 | return $blocks; |
734 | } else if (isset($blocks[$blockid])) { |
735 | return $blocks[$blockid]; |
736 | } else { |
737 | return false; |
9b4b78fd |
738 | } |
9b4b78fd |
739 | } |
740 | |
741 | function blocks_find_block($blockid, $blocksarray) { |
0d6b9d4f |
742 | if (empty($blocksarray)) { |
743 | return false; |
744 | } |
9b4b78fd |
745 | foreach($blocksarray as $blockgroup) { |
0d6b9d4f |
746 | if (empty($blockgroup)) { |
747 | continue; |
748 | } |
9b4b78fd |
749 | foreach($blockgroup as $instance) { |
750 | if($instance->blockid == $blockid) { |
751 | return $instance; |
752 | } |
753 | } |
754 | } |
755 | return false; |
756 | } |
757 | |
758 | function blocks_find_instance($instanceid, $blocksarray) { |
759 | foreach($blocksarray as $subarray) { |
760 | foreach($subarray as $instance) { |
761 | if($instance->id == $instanceid) { |
762 | return $instance; |
763 | } |
764 | } |
765 | } |
766 | return false; |
767 | } |
768 | |
ec79d3e4 |
769 | // Simple entry point for anyone that wants to use blocks |
ee6055eb |
770 | function blocks_setup(&$PAGE,$pinned=BLOCKS_PINNED_FALSE) { |
771 | switch ($pinned) { |
772 | case BLOCKS_PINNED_TRUE: |
773 | $pageblocks = blocks_get_pinned($PAGE); |
774 | break; |
775 | case BLOCKS_PINNED_BOTH: |
776 | $pageblocks = blocks_get_by_page_pinned($PAGE); |
777 | break; |
778 | case BLOCKS_PINNED_FALSE: |
779 | default: |
780 | $pageblocks = blocks_get_by_page($PAGE); |
781 | break; |
782 | } |
783 | blocks_execute_url_action($PAGE, $pageblocks,($pinned==BLOCKS_PINNED_TRUE)); |
ec79d3e4 |
784 | return $pageblocks; |
785 | } |
786 | |
b1631fef |
787 | function blocks_execute_action($page, &$pageblocks, $blockaction, $instanceorid, $pinned=false, $redirect=true) { |
58ff964f |
788 | global $CFG, $USER, $DB; |
9b4b78fd |
789 | |
a9c75a9c |
790 | if (is_int($instanceorid)) { |
9b4b78fd |
791 | $blockid = $instanceorid; |
a9c75a9c |
792 | } else if (is_object($instanceorid)) { |
9b4b78fd |
793 | $instance = $instanceorid; |
794 | } |
0f3fe4b6 |
795 | |
796 | switch($blockaction) { |
9b4b78fd |
797 | case 'config': |
9b4b78fd |
798 | $block = blocks_get_record($instance->blockid); |
e82d6cac |
799 | // Hacky hacky tricky stuff to get the original human readable block title, |
800 | // even if the block has configured its title to be something else. |
afd1ec02 |
801 | // Create the object WITHOUT instance data. |
e82d6cac |
802 | $blockobject = block_instance($block->name); |
9b4b78fd |
803 | if ($blockobject === false) { |
11306331 |
804 | break; |
805 | } |
afd1ec02 |
806 | |
11306331 |
807 | // First of all check to see if the block wants to be edited |
808 | if(!$blockobject->user_can_edit()) { |
809 | break; |
9b4b78fd |
810 | } |
11306331 |
811 | |
e82d6cac |
812 | // Now get the title and AFTER that load up the instance |
813 | $blocktitle = $blockobject->get_title(); |
814 | $blockobject->_load_instance($instance); |
afd1ec02 |
815 | |
27ec21a0 |
816 | // Define the data we're going to silently include in the instance config form here, |
9b4b78fd |
817 | // so we can strip them from the submitted data BEFORE serializing it. |
818 | $hiddendata = array( |
19f5b2db |
819 | 'sesskey' => sesskey(), |
9b4b78fd |
820 | 'instanceid' => $instance->id, |
821 | 'blockaction' => 'config' |
822 | ); |
f032aa7a |
823 | |
824 | // To this data, add anything the page itself needs to display |
ad52c04f |
825 | $hiddendata = $page->url->params($hiddendata); |
9b4b78fd |
826 | |
294ce987 |
827 | if ($data = data_submitted()) { |
9b4b78fd |
828 | $remove = array_keys($hiddendata); |
829 | foreach($remove as $item) { |
830 | unset($data->$item); |
0f3fe4b6 |
831 | } |
58ff964f |
832 | if(!$blockobject->instance_config_save($data, $pinned)) { |
e49ef64a |
833 | print_error('cannotsaveblock'); |
0f3fe4b6 |
834 | } |
9b4b78fd |
835 | // And nothing more, continue with displaying the page |
0f3fe4b6 |
836 | } |
9b4b78fd |
837 | else { |
f032aa7a |
838 | // We need to show the config screen, so we highjack the display logic and then die |
e82d6cac |
839 | $strheading = get_string('blockconfiga', 'moodle', $blocktitle); |
edb42f09 |
840 | $page->print_header(get_string('pageheaderconfigablock', 'moodle'), array($strheading => '')); |
b9709905 |
841 | |
842 | echo '<div class="block-config" id="'.$block->name.'">'; /// Make CSS easier |
0be6f678 |
843 | |
edb42f09 |
844 | print_heading($strheading); |
ad52c04f |
845 | echo '<form method="post" name="block-config" action="'. $page->url->out(false) .'">'; |
9b4b78fd |
846 | echo '<p>'; |
847 | foreach($hiddendata as $name => $val) { |
27ec21a0 |
848 | echo '<input type="hidden" name="'. $name .'" value="'. $val .'" />'; |
0f3fe4b6 |
849 | } |
9b4b78fd |
850 | echo '</p>'; |
851 | $blockobject->instance_config_print(); |
852 | echo '</form>'; |
b9709905 |
853 | |
854 | echo '</div>'; |
ad5d5997 |
855 | $PAGE->set_pagetype('blocks-' . $block->name); |
9b4b78fd |
856 | print_footer(); |
f032aa7a |
857 | die(); // Do not go on with the other page-related stuff |
0f3fe4b6 |
858 | } |
859 | break; |
9b4b78fd |
860 | case 'toggle': |
861 | if(empty($instance)) { |
e49ef64a |
862 | print_error('invalidblockinstance', '', '', $blockaction); |
0f3fe4b6 |
863 | } |
9b4b78fd |
864 | $instance->visible = ($instance->visible) ? 0 : 1; |
0d6b9d4f |
865 | if (!empty($pinned)) { |
66b10689 |
866 | $DB->update_record('block_pinned_old', $instance); |
0d6b9d4f |
867 | } else { |
66b10689 |
868 | $DB->update_record('block_instance_old', $instance); |
0d6b9d4f |
869 | } |
9b4b78fd |
870 | break; |
871 | case 'delete': |
872 | if(empty($instance)) { |
e49ef64a |
873 | print_error('invalidblockinstance', '', '', $blockaction); |
0f3fe4b6 |
874 | } |
0d6b9d4f |
875 | blocks_delete_instance($instance, $pinned); |
0f3fe4b6 |
876 | break; |
877 | case 'moveup': |
9b4b78fd |
878 | if(empty($instance)) { |
e49ef64a |
879 | print_error('invalidblockinstance', '', '', $blockaction); |
9b4b78fd |
880 | } |
f032aa7a |
881 | |
882 | if($instance->weight == 0) { |
883 | // The block is the first one, so a move "up" probably means it changes position |
884 | // Where is the instance going to be moved? |
885 | $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_UP); |
6b853ff4 |
886 | $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); |
f032aa7a |
887 | |
0d6b9d4f |
888 | blocks_execute_repositioning($instance, $newpos, $newweight, $pinned); |
89a5baab |
889 | } |
f032aa7a |
890 | else { |
891 | // The block is just moving upwards in the same position. |
892 | // This configuration will make sure that even if somehow the weights |
893 | // become not continuous, block move operations will eventually bring |
894 | // the situation back to normal without printing any warnings. |
895 | if(!empty($pageblocks[$instance->position][$instance->weight - 1])) { |
896 | $other = $pageblocks[$instance->position][$instance->weight - 1]; |
897 | } |
898 | if(!empty($other)) { |
899 | ++$other->weight; |
0d6b9d4f |
900 | if (!empty($pinned)) { |
66b10689 |
901 | $DB->update_record('block_pinned_old', $other); |
0d6b9d4f |
902 | } else { |
66b10689 |
903 | $DB->update_record('block_instance_old', $other); |
afd1ec02 |
904 | } |
f032aa7a |
905 | } |
906 | --$instance->weight; |
0d6b9d4f |
907 | if (!empty($pinned)) { |
66b10689 |
908 | $DB->update_record('block_pinned_old', $instance); |
0d6b9d4f |
909 | } else { |
66b10689 |
910 | $DB->update_record('block_instance_old', $instance); |
0d6b9d4f |
911 | } |
0f3fe4b6 |
912 | } |
913 | break; |
914 | case 'movedown': |
9b4b78fd |
915 | if(empty($instance)) { |
e49ef64a |
916 | print_error('invalidblockinstance', '', '', $blockaction); |
9b4b78fd |
917 | } |
f032aa7a |
918 | |
919 | if($instance->weight == max(array_keys($pageblocks[$instance->position]))) { |
920 | // The block is the last one, so a move "down" probably means it changes position |
921 | // Where is the instance going to be moved? |
922 | $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_DOWN); |
6b853ff4 |
923 | $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); |
f032aa7a |
924 | |
0d6b9d4f |
925 | blocks_execute_repositioning($instance, $newpos, $newweight, $pinned); |
89a5baab |
926 | } |
f032aa7a |
927 | else { |
928 | // The block is just moving downwards in the same position. |
929 | // This configuration will make sure that even if somehow the weights |
930 | // become not continuous, block move operations will eventually bring |
931 | // the situation back to normal without printing any warnings. |
932 | if(!empty($pageblocks[$instance->position][$instance->weight + 1])) { |
933 | $other = $pageblocks[$instance->position][$instance->weight + 1]; |
934 | } |
935 | if(!empty($other)) { |
936 | --$other->weight; |
0d6b9d4f |
937 | if (!empty($pinned)) { |
66b10689 |
938 | $DB->update_record('block_pinned_old', $other); |
0d6b9d4f |
939 | } else { |
66b10689 |
940 | $DB->update_record('block_instance_old', $other); |
0d6b9d4f |
941 | } |
f032aa7a |
942 | } |
943 | ++$instance->weight; |
0d6b9d4f |
944 | if (!empty($pinned)) { |
66b10689 |
945 | $DB->update_record('block_pinned_old', $instance); |
0d6b9d4f |
946 | } else { |
66b10689 |
947 | $DB->update_record('block_instance_old', $instance); |
0d6b9d4f |
948 | } |
0f3fe4b6 |
949 | } |
950 | break; |
9b4b78fd |
951 | case 'moveleft': |
952 | if(empty($instance)) { |
e49ef64a |
953 | print_error('invalidblockinstance', '', '', $blockaction); |
9b4b78fd |
954 | } |
f032aa7a |
955 | |
956 | // Where is the instance going to be moved? |
957 | $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_LEFT); |
6b853ff4 |
958 | $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); |
f032aa7a |
959 | |
0d6b9d4f |
960 | blocks_execute_repositioning($instance, $newpos, $newweight, $pinned); |
0f3fe4b6 |
961 | break; |
9b4b78fd |
962 | case 'moveright': |
963 | if(empty($instance)) { |
e49ef64a |
964 | print_error('invalidblockinstance', '', '', $blockaction); |
9b4b78fd |
965 | } |
f032aa7a |
966 | |
967 | // Where is the instance going to be moved? |
968 | $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_RIGHT); |
6b853ff4 |
969 | $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); |
f032aa7a |
970 | |
0d6b9d4f |
971 | blocks_execute_repositioning($instance, $newpos, $newweight, $pinned); |
9b4b78fd |
972 | break; |
973 | case 'add': |
974 | // Add a new instance of this block, if allowed |
975 | $block = blocks_get_record($blockid); |
0f3fe4b6 |
976 | |
3cacefda |
977 | if(empty($block) || !$block->visible) { |
978 | // Only allow adding if the block exists and is enabled |
11306331 |
979 | break; |
9b4b78fd |
980 | } |
0f3fe4b6 |
981 | |
89a5baab |
982 | if(!$block->multiple && blocks_find_block($blockid, $pageblocks) !== false) { |
983 | // If no multiples are allowed and we already have one, return now |
11306331 |
984 | break; |
985 | } |
986 | |
987 | if(!block_method_result($block->name, 'user_can_addto', $page)) { |
988 | // If the block doesn't want to be added... |
989 | break; |
89a5baab |
990 | } |
991 | |
86b5ea0f |
992 | $newpos = $page->blocks->get_default_region(); |
0d6b9d4f |
993 | if (!empty($pinned)) { |
58ff964f |
994 | $sql = "SELECT 1, MAX(weight) + 1 AS nextfree |
66b10689 |
995 | FROM {block_pinned_old} |
58ff964f |
996 | WHERE pagetype = ? AND position = ?"; |
f230ce19 |
997 | $params = array($page->pagetype, $newpos); |
58ff964f |
998 | |
0d6b9d4f |
999 | } else { |
58ff964f |
1000 | $sql = "SELECT 1, MAX(weight) + 1 AS nextfree |
66b10689 |
1001 | FROM {block_instance_old} |
58ff964f |
1002 | WHERE pageid = ? AND pagetype = ? AND position = ?"; |
f230ce19 |
1003 | $params = array($page->get_id(), $page->pagetype, $newpos); |
0d6b9d4f |
1004 | } |
58ff964f |
1005 | $weight = $DB->get_record_sql($sql, $params); |
9b4b78fd |
1006 | |
1007 | $newinstance = new stdClass; |
1008 | $newinstance->blockid = $blockid; |
0d6b9d4f |
1009 | if (empty($pinned)) { |
1010 | $newinstance->pageid = $page->get_id(); |
1011 | } |
f230ce19 |
1012 | $newinstance->pagetype = $page->pagetype; |
f032aa7a |
1013 | $newinstance->position = $newpos; |
ff679897 |
1014 | $newinstance->weight = empty($weight->nextfree) ? 0 : $weight->nextfree; |
9b4b78fd |
1015 | $newinstance->visible = 1; |
1016 | $newinstance->configdata = ''; |
0d6b9d4f |
1017 | if (!empty($pinned)) { |
66b10689 |
1018 | $newinstance->id = $DB->insert_record('block_pinned_old', $newinstance); |
0d6b9d4f |
1019 | } else { |
66b10689 |
1020 | $newinstance->id = $DB->insert_record('block_instance_old', $newinstance); |
0d6b9d4f |
1021 | } |
b33dd23a |
1022 | |
1023 | // If the new instance was created, allow it to do additional setup |
1024 | if($newinstance && ($obj = block_instance($block->name, $newinstance))) { |
1025 | // Return value ignored |
1026 | $obj->instance_create(); |
1027 | } |
1028 | |
9b4b78fd |
1029 | break; |
1030 | } |
f032aa7a |
1031 | |
b1631fef |
1032 | if ($redirect) { |
1033 | // In order to prevent accidental duplicate actions, redirect to a page with a clean url |
ad52c04f |
1034 | redirect($page->url->out()); |
b1631fef |
1035 | } |
f032aa7a |
1036 | } |
1037 | |
da71112b |
1038 | // You can use this to get the blocks to respond to URL actions without much hassle |
0d6b9d4f |
1039 | function blocks_execute_url_action(&$PAGE, &$pageblocks,$pinned=false) { |
02cc05a7 |
1040 | $blockaction = optional_param('blockaction', '', PARAM_ALPHA); |
da71112b |
1041 | |
3edc57e1 |
1042 | if (empty($blockaction) || !$PAGE->user_allowed_editing() || !confirm_sesskey()) { |
da71112b |
1043 | return; |
1044 | } |
1045 | |
1046 | $instanceid = optional_param('instanceid', 0, PARAM_INT); |
1047 | $blockid = optional_param('blockid', 0, PARAM_INT); |
afd1ec02 |
1048 | |
da71112b |
1049 | if (!empty($blockid)) { |
0d6b9d4f |
1050 | blocks_execute_action($PAGE, $pageblocks, strtolower($blockaction), $blockid, $pinned); |
da71112b |
1051 | |
1052 | } |
1053 | else if (!empty($instanceid)) { |
1054 | $instance = blocks_find_instance($instanceid, $pageblocks); |
0d6b9d4f |
1055 | blocks_execute_action($PAGE, $pageblocks, strtolower($blockaction), $instance, $pinned); |
da71112b |
1056 | } |
1057 | } |
1058 | |
f032aa7a |
1059 | // This shouldn't be used externally at all, it's here for use by blocks_execute_action() |
1060 | // in order to reduce code repetition. |
29ca8b88 |
1061 | function blocks_execute_repositioning(&$instance, $newpos, $newweight, $pinned=false) { |
58ff964f |
1062 | global $DB; |
f032aa7a |
1063 | |
c4308cfa |
1064 | // If it's staying where it is, don't do anything, unless overridden |
29ca8b88 |
1065 | if ($newpos == $instance->position) { |
f032aa7a |
1066 | return; |
1067 | } |
1068 | |
1069 | // Close the weight gap we 'll leave behind |
0d6b9d4f |
1070 | if (!empty($pinned)) { |
66b10689 |
1071 | $sql = "UPDATE {block_instance_old} |
58ff964f |
1072 | SET weight = weight - 1 |
1073 | WHERE pagetype = ? AND position = ? AND weight > ?"; |
1074 | $params = array($instance->pagetype, $instance->position, $instance->weight); |
1075 | |
0d6b9d4f |
1076 | } else { |
66b10689 |
1077 | $sql = "UPDATE {block_instance_old} |
58ff964f |
1078 | SET weight = weight - 1 |
1079 | WHERE pagetype = ? AND pageid = ? |
1080 | AND position = ? AND weight > ?"; |
1081 | $params = array($instance->pagetype, $instance->pageid, $instance->position, $instance->weight); |
0d6b9d4f |
1082 | } |
58ff964f |
1083 | $DB->execute($sql, $params); |
f032aa7a |
1084 | |
1085 | $instance->position = $newpos; |
1086 | $instance->weight = $newweight; |
1087 | |
0d6b9d4f |
1088 | if (!empty($pinned)) { |
66b10689 |
1089 | $DB->update_record('block_pinned_old', $instance); |
0d6b9d4f |
1090 | } else { |
66b10689 |
1091 | $DB->update_record('block_instance_old', $instance); |
0d6b9d4f |
1092 | } |
1093 | } |
1094 | |
29ca8b88 |
1095 | |
1096 | /** |
1097 | * Moves a block to the new position (column) and weight (sort order). |
1098 | * @param $instance - The block instance to be moved. |
1099 | * @param $destpos - BLOCK_POS_LEFT or BLOCK_POS_RIGHT. The destination column. |
1100 | * @param $destweight - The destination sort order. If NULL, we add to the end |
1101 | * of the destination column. |
1102 | * @param $pinned - Are we moving pinned blocks? We can only move pinned blocks |
1103 | * to a new position withing the pinned list. Likewise, we |
1104 | * can only moved non-pinned blocks to a new position within |
1105 | * the non-pinned list. |
1106 | * @return boolean (success or failure). |
1107 | */ |
1108 | function blocks_move_block($page, &$instance, $destpos, $destweight=NULL, $pinned=false) { |
58ff964f |
1109 | global $CFG, $DB; |
afd1ec02 |
1110 | |
29ca8b88 |
1111 | if ($pinned) { |
1112 | $blocklist = blocks_get_pinned($page); |
1113 | } else { |
1114 | $blocklist = blocks_get_by_page($page); |
1115 | } |
afd1ec02 |
1116 | |
29ca8b88 |
1117 | if ($blocklist[$instance->position][$instance->weight]->id != $instance->id) { |
1118 | // The source block instance is not where we think it is. |
c4308cfa |
1119 | return false; |
d23157d8 |
1120 | } |
afd1ec02 |
1121 | |
29ca8b88 |
1122 | // First we close the gap that will be left behind when we take out the |
1123 | // block from it's current column. |
1124 | if ($pinned) { |
66b10689 |
1125 | $closegapsql = "UPDATE {block_instance_old} |
afd1ec02 |
1126 | SET weight = weight - 1 |
58ff964f |
1127 | WHERE weight > ? AND position = ? AND pagetype = ?"; |
1128 | $params = array($instance->weight, $instance->position, $instance->pagetype); |
e028ed34 |
1129 | } else { |
66b10689 |
1130 | $closegapsql = "UPDATE {block_instance_old} |
afd1ec02 |
1131 | SET weight = weight - 1 |
58ff964f |
1132 | WHERE weight > ? AND position = ? |
1133 | AND pagetype = ? AND pageid = ?"; |
1134 | $params = array($instance->weight, $instance->position, $instance->pagetype, $instance->pageid); |
29ca8b88 |
1135 | } |
58ff964f |
1136 | if (!$DB->execute($closegapsql, $params)) { |
29ca8b88 |
1137 | return false; |
77e65ff7 |
1138 | } |
afd1ec02 |
1139 | |
29ca8b88 |
1140 | // Now let's make space for the block being moved. |
1141 | if ($pinned) { |
66b10689 |
1142 | $opengapsql = "UPDATE {block_instance_old} |
afd1ec02 |
1143 | SET weight = weight + 1 |
58ff964f |
1144 | WHERE weight >= ? AND position = ? AND pagetype = ?"; |
1145 | $params = array($destweight, $destpos, $instance->pagetype); |
d23157d8 |
1146 | } else { |
66b10689 |
1147 | $opengapsql = "UPDATE {block_instance_old} |
58ff964f |
1148 | SET weight = weight + 1 |
1149 | WHERE weight >= ? AND position = ? |
1150 | AND pagetype = ? AND pageid = ?"; |
1151 | $params = array($destweight, $destpos, $instance->pagetype, $instance->pageid); |
29ca8b88 |
1152 | } |
655b09ca |
1153 | if (!$DB->execute($opengapsql, $params)) { |
29ca8b88 |
1154 | return false; |
c4308cfa |
1155 | } |
afd1ec02 |
1156 | |
29ca8b88 |
1157 | // Move the block. |
1158 | $instance->position = $destpos; |
1159 | $instance->weight = $destweight; |
e028ed34 |
1160 | |
29ca8b88 |
1161 | if ($pinned) { |
66b10689 |
1162 | $table = 'block_pinned_old'; |
29ca8b88 |
1163 | } else { |
66b10689 |
1164 | $table = 'block_instance_old'; |
29ca8b88 |
1165 | } |
58ff964f |
1166 | return $DB->update_record($table, $instance); |
e028ed34 |
1167 | } |
1168 | |
d23157d8 |
1169 | |
1170 | /** |
1171 | * Returns an array consisting of 2 arrays: |
1172 | * 1) Array of pinned blocks for position BLOCK_POS_LEFT |
1173 | * 2) Array of pinned blocks for position BLOCK_POS_RIGHT |
1174 | */ |
0d6b9d4f |
1175 | function blocks_get_pinned($page) { |
58ff964f |
1176 | global $DB; |
afd1ec02 |
1177 | |
0d6b9d4f |
1178 | $visible = true; |
58ff964f |
1179 | $select = "pagetype = ?"; |
f230ce19 |
1180 | $params = array($page->pagetype); |
58ff964f |
1181 | |
1182 | if ($visible) { |
1183 | $select .= " AND visible = 1"; |
1184 | } |
1185 | |
66b10689 |
1186 | $blocks = $DB->get_records_select('block_pinned_old', $select, $params, 'position, weight'); |
0d6b9d4f |
1187 | |
86b5ea0f |
1188 | $positions = $page->blocks->get_regions(); |
0d6b9d4f |
1189 | $arr = array(); |
1190 | |
1191 | foreach($positions as $key => $position) { |
1192 | $arr[$position] = array(); |
1193 | } |
1194 | |
1195 | if(empty($blocks)) { |
1196 | return $arr; |
1197 | } |
1198 | |
1199 | foreach($blocks as $block) { |
1200 | $block->pinned = true; // so we know we can't move it. |
ddf1935f |
1201 | // make up an instanceid if we can.. |
1202 | $block->pageid = $page->get_id(); |
0d6b9d4f |
1203 | $arr[$block->position][$block->weight] = $block; |
1204 | } |
1205 | |
afd1ec02 |
1206 | return $arr; |
0d6b9d4f |
1207 | } |
1208 | |
1209 | |
d23157d8 |
1210 | /** |
1211 | * Similar to blocks_get_by_page(), except that, the array returned includes |
1212 | * pinned blocks as well. Pinned blocks are always appended before normal |
1213 | * block instances. |
1214 | */ |
0d6b9d4f |
1215 | function blocks_get_by_page_pinned($page) { |
1216 | $pinned = blocks_get_pinned($page); |
1217 | $user = blocks_get_by_page($page); |
afd1ec02 |
1218 | |
0d6b9d4f |
1219 | $weights = array(); |
1220 | |
1221 | foreach ($pinned as $pos => $arr) { |
1222 | $weights[$pos] = count($arr); |
1223 | } |
1224 | |
1225 | foreach ($user as $pos => $blocks) { |
1226 | if (!array_key_exists($pos,$pinned)) { |
1227 | $pinned[$pos] = array(); |
1228 | } |
1229 | if (!array_key_exists($pos,$weights)) { |
1230 | $weights[$pos] = 0; |
1231 | } |
77e65ff7 |
1232 | foreach ($blocks as $block) { |
0d6b9d4f |
1233 | $pinned[$pos][$weights[$pos]] = $block; |
1234 | $weights[$pos]++; |
1235 | } |
1236 | } |
1237 | return $pinned; |
0f3fe4b6 |
1238 | } |
1239 | |
d23157d8 |
1240 | |
1241 | /** |
1242 | * Returns an array of blocks for the page. Pinned blocks are excluded. |
1243 | */ |
9b4b78fd |
1244 | function blocks_get_by_page($page) { |
58ff964f |
1245 | global $DB; |
1246 | |
66b10689 |
1247 | $blocks = $DB->get_records_select('block_instance_old', "pageid = ? AND ? LIKE (" . $DB->sql_concat('pagetype', "'%'") . ")", |
f230ce19 |
1248 | array($page->get_id(), $page->pagetype), 'position, weight'); |
f032aa7a |
1249 | |
86b5ea0f |
1250 | $positions = $page->blocks->get_regions(); |
f032aa7a |
1251 | $arr = array(); |
1252 | foreach($positions as $key => $position) { |
1253 | $arr[$position] = array(); |
1254 | } |
0f3fe4b6 |
1255 | |
9b4b78fd |
1256 | if(empty($blocks)) { |
1257 | return $arr; |
1258 | } |
0f3fe4b6 |
1259 | |
77e65ff7 |
1260 | foreach($blocks as $block) { |
9b4b78fd |
1261 | $arr[$block->position][$block->weight] = $block; |
0f3fe4b6 |
1262 | } |
d23157d8 |
1263 | return $arr; |
9b4b78fd |
1264 | } |
0f3fe4b6 |
1265 | |
d23157d8 |
1266 | |
9b4b78fd |
1267 | //This function prints the block to admin blocks as necessary |
c1d8705f |
1268 | function blocks_print_adminblock(&$page, &$pageblocks) { |
9b4b78fd |
1269 | global $USER; |
0f3fe4b6 |
1270 | |
08eab897 |
1271 | $missingblocks = array_keys($page->blocks->get_addable_blocks()); |
c1d8705f |
1272 | |
9b4b78fd |
1273 | if (!empty($missingblocks)) { |
74fd9ff9 |
1274 | $strblocks = '<div class="title"><h2>'; |
303fe9f4 |
1275 | $strblocks .= get_string('blocks'); |
552adc27 |
1276 | $strblocks .= '</h2></div>'; |
c1d8705f |
1277 | $stradd = get_string('add'); |
9b4b78fd |
1278 | foreach ($missingblocks as $blockid) { |
1279 | $block = blocks_get_record($blockid); |
9b4b78fd |
1280 | $blockobject = block_instance($block->name); |
1281 | if ($blockobject === false) { |
1282 | continue; |
1283 | } |
11306331 |
1284 | if(!$blockobject->user_can_addto($page)) { |
1285 | continue; |
1286 | } |
9b4b78fd |
1287 | $menu[$block->id] = $blockobject->get_title(); |
1288 | } |
4a4c30d2 |
1289 | asort($menu); |
0f3fe4b6 |
1290 | |
ad52c04f |
1291 | $target = $page->url->out(array('sesskey' => sesskey(), 'blockaction' => 'add')); |
f032aa7a |
1292 | $content = popup_form($target.'&blockid=', $menu, 'add_block', '', $stradd .'...', '', '', true); |
afd8402c |
1293 | print_side_block($strblocks, $content, NULL, NULL, NULL, array('class' => 'block_adminblock')); |
0f3fe4b6 |
1294 | } |
0f3fe4b6 |
1295 | } |
1296 | |
19f5b2db |
1297 | /** |
1298 | * Delete all the blocks from a particular page. |
1299 | * |
1300 | * @param string $pagetype the page type. |
1301 | * @param integer $pageid the page id. |
1302 | * @return success of failure. |
1303 | */ |
1304 | function blocks_delete_all_on_page($pagetype, $pageid) { |
1305 | global $DB; |
66b10689 |
1306 | if ($instances = $DB->get_records('block_instance_old', array('pageid' => $pageid, 'pagetype' => $pagetype))) { |
19f5b2db |
1307 | foreach ($instances as $instance) { |
1308 | delete_context(CONTEXT_BLOCK, $instance->id); // Ingore any failures here. |
1309 | } |
1310 | } |
66b10689 |
1311 | return $DB->delete_records('block_instance_old', array('pageid' => $pageid, 'pagetype' => $pagetype)); |
19f5b2db |
1312 | } |
1313 | |
1314 | // Dispite what this function is called, it seems to be mostly used to populate |
1315 | // the default blocks when a new course (or whatever) is created. |
9b4b78fd |
1316 | function blocks_repopulate_page($page) { |
7e0489f4 |
1317 | global $CFG, $DB; |
5b224948 |
1318 | |
9b4b78fd |
1319 | $allblocks = blocks_get_record(); |
1320 | |
1321 | if(empty($allblocks)) { |
e49ef64a |
1322 | print_error('cannotgetblock'); |
9b4b78fd |
1323 | } |
1324 | |
f032aa7a |
1325 | // Assemble the information to correlate block names to ids |
9b4b78fd |
1326 | $idforname = array(); |
1327 | foreach($allblocks as $block) { |
1328 | $idforname[$block->name] = $block->id; |
1329 | } |
1330 | |
f032aa7a |
1331 | /// If the site override has been defined, it is the only valid one. |
1332 | if (!empty($CFG->defaultblocks_override)) { |
1333 | $blocknames = $CFG->defaultblocks_override; |
1334 | } |
1335 | else { |
1336 | $blocknames = $page->blocks_get_default(); |
1337 | } |
afd1ec02 |
1338 | |
86b5ea0f |
1339 | $positions = $page->blocks->get_regions(); |
f032aa7a |
1340 | $posblocks = explode(':', $blocknames); |
1341 | |
1342 | // Now one array holds the names of the positions, and the other one holds the blocks |
1343 | // that are going to go in each position. Luckily for us, both arrays are numerically |
1344 | // indexed and the indexes match, so we can work straight away... but CAREFULLY! |
9b4b78fd |
1345 | |
f032aa7a |
1346 | // Ready to start creating block instances, but first drop any existing ones |
f230ce19 |
1347 | blocks_delete_all_on_page($page->pagetype, $page->get_id()); |
f032aa7a |
1348 | |
1349 | // Here we slyly count $posblocks and NOT $positions. This can actually make a difference |
1350 | // if the textual representation has undefined slots in the end. So we only work with as many |
1351 | // positions were retrieved, not with all the page says it has available. |
1352 | $numpositions = count($posblocks); |
1353 | for($i = 0; $i < $numpositions; ++$i) { |
1354 | $position = $positions[$i]; |
1355 | $blocknames = explode(',', $posblocks[$i]); |
9b4b78fd |
1356 | $weight = 0; |
1357 | foreach($blocknames as $blockname) { |
1358 | $newinstance = new stdClass; |
1359 | $newinstance->blockid = $idforname[$blockname]; |
f032aa7a |
1360 | $newinstance->pageid = $page->get_id(); |
f230ce19 |
1361 | $newinstance->pagetype = $page->pagetype; |
9b4b78fd |
1362 | $newinstance->position = $position; |
1363 | $newinstance->weight = $weight; |
1364 | $newinstance->visible = 1; |
1365 | $newinstance->configdata = ''; |
3cacefda |
1366 | |
1367 | if(!empty($newinstance->blockid)) { |
1368 | // Only add block if it was recognized |
66b10689 |
1369 | $DB->insert_record('block_instance_old', $newinstance); |
3cacefda |
1370 | ++$weight; |
1371 | } |
0f3fe4b6 |
1372 | } |
1373 | } |
9b4b78fd |
1374 | |
1375 | return true; |
0f3fe4b6 |
1376 | } |
1377 | |
f10306b9 |
1378 | ?> |