|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00029 defined('MOODLE_INTERNAL') || die(); 00030 00034 define('BLOCK_MOVE_LEFT', 0x01); 00035 define('BLOCK_MOVE_RIGHT', 0x02); 00036 define('BLOCK_MOVE_UP', 0x04); 00037 define('BLOCK_MOVE_DOWN', 0x08); 00038 define('BLOCK_CONFIGURE', 0x10); 00044 define('BLOCK_POS_LEFT', 'side-pre'); 00045 define('BLOCK_POS_RIGHT', 'side-post'); 00051 define('BLOCKS_PINNED_TRUE',0); 00052 define('BLOCKS_PINNED_FALSE',1); 00053 define('BLOCKS_PINNED_BOTH',2); 00056 define('BUI_CONTEXTS_FRONTPAGE_ONLY', 0); 00057 define('BUI_CONTEXTS_FRONTPAGE_SUBS', 1); 00058 define('BUI_CONTEXTS_ENTIRE_SITE', 2); 00059 00060 define('BUI_CONTEXTS_CURRENT', 0); 00061 define('BUI_CONTEXTS_CURRENT_SUBS', 1); 00062 00071 class block_not_on_page_exception extends moodle_exception { 00077 public function __construct($instanceid, $page) { 00078 $a = new stdClass; 00079 $a->instanceid = $instanceid; 00080 $a->url = $page->url->out(); 00081 parent::__construct('blockdoesnotexistonpage', '', $page->url->out(), $a); 00082 } 00083 } 00084 00094 class block_manager { 00099 const MAX_WEIGHT = 10; 00100 00102 00107 protected $page; 00108 00110 protected $regions = array(); 00111 00113 protected $defaultregion = null; 00114 00116 protected $allblocks = null; 00117 00123 protected $addableblocks = null; 00124 00129 protected $birecordsbyregion = null; 00130 00136 protected $blockinstances = array(); 00137 00143 protected $visibleblockcontent = array(); 00144 00150 protected $extracontent = array(); 00151 00161 protected $movingblock = null; 00162 00166 protected $fakeblocksonly = false; 00167 00169 00176 public function __construct($page) { 00177 $this->page = $page; 00178 } 00179 00181 00187 public function get_regions() { 00188 if (is_null($this->defaultregion)) { 00189 $this->page->initialise_theme_and_output(); 00190 } 00191 return array_keys($this->regions); 00192 } 00193 00202 public function get_default_region() { 00203 $this->page->initialise_theme_and_output(); 00204 return $this->defaultregion; 00205 } 00206 00212 public function get_addable_blocks() { 00213 $this->check_is_loaded(); 00214 00215 if (!is_null($this->addableblocks)) { 00216 return $this->addableblocks; 00217 } 00218 00219 // Lazy load. 00220 $this->addableblocks = array(); 00221 00222 $allblocks = blocks_get_record(); 00223 if (empty($allblocks)) { 00224 return $this->addableblocks; 00225 } 00226 00227 $pageformat = $this->page->pagetype; 00228 foreach($allblocks as $block) { 00229 if ($block->visible && 00230 (block_method_result($block->name, 'instance_allow_multiple') || !$this->is_block_present($block->name)) && 00231 blocks_name_allowed_in_format($block->name, $pageformat) && 00232 block_method_result($block->name, 'user_can_addto', $this->page)) { 00233 $this->addableblocks[$block->name] = $block; 00234 } 00235 } 00236 00237 return $this->addableblocks; 00238 } 00239 00246 public function is_block_present($blockname) { 00247 if (empty($this->blockinstances)) { 00248 return false; 00249 } 00250 00251 foreach ($this->blockinstances as $region) { 00252 foreach ($region as $instance) { 00253 if (empty($instance->instance->blockname)) { 00254 continue; 00255 } 00256 if ($instance->instance->blockname == $blockname) { 00257 return true; 00258 } 00259 } 00260 } 00261 return false; 00262 } 00263 00271 public function is_known_block_type($blockname, $includeinvisible = false) { 00272 $blocks = $this->get_installed_blocks(); 00273 foreach ($blocks as $block) { 00274 if ($block->name == $blockname && ($includeinvisible || $block->visible)) { 00275 return true; 00276 } 00277 } 00278 return false; 00279 } 00280 00287 public function is_known_region($region) { 00288 return array_key_exists($region, $this->regions); 00289 } 00290 00297 public function get_blocks_for_region($region) { 00298 $this->check_is_loaded(); 00299 $this->ensure_instances_exist($region); 00300 return $this->blockinstances[$region]; 00301 } 00302 00309 public function get_content_for_region($region, $output) { 00310 $this->check_is_loaded(); 00311 $this->ensure_content_created($region, $output); 00312 return $this->visibleblockcontent[$region]; 00313 } 00314 00322 protected function get_move_target_url($region, $weight) { 00323 return new moodle_url($this->page->url, array('bui_moveid' => $this->movingblock, 00324 'bui_newregion' => $region, 'bui_newweight' => $weight, 'sesskey' => sesskey())); 00325 } 00326 00343 public function region_has_content($region, $output) { 00344 00345 if (!$this->is_known_region($region)) { 00346 return false; 00347 } 00348 $this->check_is_loaded(); 00349 $this->ensure_content_created($region, $output); 00350 // if ($this->page->user_is_editing() && $this->page->user_can_edit_blocks()) { 00351 // Mark Nielsen's patch - part 1 00352 if ($this->page->user_is_editing() && $this->page->user_can_edit_blocks() && $this->movingblock) { 00353 // If editing is on, we need all the block regions visible, for the 00354 // move blocks UI. 00355 return true; 00356 } 00357 return !empty($this->visibleblockcontent[$region]) || !empty($this->extracontent[$region]); 00358 } 00359 00365 public function get_installed_blocks() { 00366 global $DB; 00367 if (is_null($this->allblocks)) { 00368 $this->allblocks = $DB->get_records('block'); 00369 } 00370 return $this->allblocks; 00371 } 00372 00374 00382 public function add_region($region) { 00383 $this->check_not_yet_loaded(); 00384 $this->regions[$region] = 1; 00385 } 00386 00393 public function add_regions($regions) { 00394 foreach ($regions as $region) { 00395 $this->add_region($region); 00396 } 00397 } 00398 00406 public function set_default_region($defaultregion) { 00407 $this->check_not_yet_loaded(); 00408 if ($defaultregion) { 00409 $this->check_region_is_known($defaultregion); 00410 } 00411 $this->defaultregion = $defaultregion; 00412 } 00413 00421 public function add_fake_block($bc, $region) { 00422 $this->page->initialise_theme_and_output(); 00423 if (!$this->is_known_region($region)) { 00424 $region = $this->get_default_region(); 00425 } 00426 if (array_key_exists($region, $this->visibleblockcontent)) { 00427 throw new coding_exception('block_manager has already prepared the blocks in region ' . 00428 $region . 'for output. It is too late to add a fake block.'); 00429 } 00430 $this->extracontent[$region][] = $bc; 00431 } 00432 00441 public function add_pretend_block($bc, $region) { 00442 debugging(DEBUG_DEVELOPER, 'add_pretend_block has been renamed to add_fake_block. Please rename the method call in your code.'); 00443 $this->add_fake_block($bc, $region); 00444 } 00445 00453 public function region_completely_docked($region, $output) { 00454 if (!$this->page->theme->enable_dock) { 00455 return false; 00456 } 00457 $this->check_is_loaded(); 00458 $this->ensure_content_created($region, $output); 00459 foreach($this->visibleblockcontent[$region] as $instance) { 00460 if (!empty($instance->content) && !get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) { 00461 return false; 00462 } 00463 } 00464 return true; 00465 } 00466 00474 public function region_uses_dock($regions, $output) { 00475 if (!$this->page->theme->enable_dock) { 00476 return false; 00477 } 00478 $this->check_is_loaded(); 00479 foreach((array)$regions as $region) { 00480 $this->ensure_content_created($region, $output); 00481 foreach($this->visibleblockcontent[$region] as $instance) { 00482 if(!empty($instance->content) && get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) { 00483 return true; 00484 } 00485 } 00486 } 00487 return false; 00488 } 00489 00491 00500 public function load_blocks($includeinvisible = null) { 00501 global $DB, $CFG; 00502 00503 if (!is_null($this->birecordsbyregion)) { 00504 // Already done. 00505 return; 00506 } 00507 00508 if ($CFG->version < 2009050619) { 00509 // Upgrade/install not complete. Don't try too show any blocks. 00510 $this->birecordsbyregion = array(); 00511 return; 00512 } 00513 00514 // Ensure we have been initialised. 00515 if (is_null($this->defaultregion)) { 00516 $this->page->initialise_theme_and_output(); 00517 // If there are still no block regions, then there are no blocks on this page. 00518 if (empty($this->regions)) { 00519 $this->birecordsbyregion = array(); 00520 return; 00521 } 00522 } 00523 00524 // Check if we need to load normal blocks 00525 if ($this->fakeblocksonly) { 00526 $this->birecordsbyregion = $this->prepare_per_region_arrays(); 00527 return; 00528 } 00529 00530 if (is_null($includeinvisible)) { 00531 $includeinvisible = $this->page->user_is_editing(); 00532 } 00533 if ($includeinvisible) { 00534 $visiblecheck = ''; 00535 } else { 00536 $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; 00537 } 00538 00539 $context = $this->page->context; 00540 $contexttest = 'bi.parentcontextid = :contextid2'; 00541 $parentcontextparams = array(); 00542 $parentcontextids = get_parent_contexts($context); 00543 if ($parentcontextids) { 00544 list($parentcontexttest, $parentcontextparams) = 00545 $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext'); 00546 $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.parentcontextid $parentcontexttest))"; 00547 } 00548 00549 $pagetypepatterns = matching_page_type_patterns($this->page->pagetype); 00550 list($pagetypepatterntest, $pagetypepatternparams) = 00551 $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest'); 00552 00553 list($ccselect, $ccjoin) = context_instance_preload_sql('bi.id', CONTEXT_BLOCK, 'ctx'); 00554 00555 $params = array( 00556 'subpage1' => $this->page->subpage, 00557 'subpage2' => $this->page->subpage, 00558 'contextid1' => $context->id, 00559 'contextid2' => $context->id, 00560 'pagetype' => $this->page->pagetype, 00561 ); 00562 if ($this->page->subpage === '') { 00563 $params['subpage1'] = $DB->sql_empty(); 00564 $params['subpage2'] = $DB->sql_empty(); 00565 } 00566 $sql = "SELECT 00567 bi.id, 00568 bp.id AS blockpositionid, 00569 bi.blockname, 00570 bi.parentcontextid, 00571 bi.showinsubcontexts, 00572 bi.pagetypepattern, 00573 bi.subpagepattern, 00574 bi.defaultregion, 00575 bi.defaultweight, 00576 COALESCE(bp.visible, 1) AS visible, 00577 COALESCE(bp.region, bi.defaultregion) AS region, 00578 COALESCE(bp.weight, bi.defaultweight) AS weight, 00579 bi.configdata 00580 $ccselect 00581 00582 FROM {block_instances} bi 00583 JOIN {block} b ON bi.blockname = b.name 00584 LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id 00585 AND bp.contextid = :contextid1 00586 AND bp.pagetype = :pagetype 00587 AND bp.subpage = :subpage1 00588 $ccjoin 00589 00590 WHERE 00591 $contexttest 00592 AND bi.pagetypepattern $pagetypepatterntest 00593 AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2) 00594 $visiblecheck 00595 AND b.visible = 1 00596 00597 ORDER BY 00598 COALESCE(bp.region, bi.defaultregion), 00599 COALESCE(bp.weight, bi.defaultweight), 00600 bi.id"; 00601 $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); 00602 00603 $this->birecordsbyregion = $this->prepare_per_region_arrays(); 00604 $unknown = array(); 00605 foreach ($blockinstances as $bi) { 00606 context_instance_preload($bi); 00607 if ($this->is_known_region($bi->region)) { 00608 $this->birecordsbyregion[$bi->region][] = $bi; 00609 } else { 00610 $unknown[] = $bi; 00611 } 00612 } 00613 00614 // Pages don't necessarily have a defaultregion. The one time this can 00615 // happen is when there are no theme block regions, but the script itself 00616 // has a block region in the main content area. 00617 if (!empty($this->defaultregion)) { 00618 $this->birecordsbyregion[$this->defaultregion] = 00619 array_merge($this->birecordsbyregion[$this->defaultregion], $unknown); 00620 } 00621 } 00622 00634 public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) { 00635 global $DB; 00636 // Allow invisible blocks because this is used when adding default page blocks, which 00637 // might include invisible ones if the user makes some default blocks invisible 00638 $this->check_known_block_type($blockname, true); 00639 $this->check_region_is_known($region); 00640 00641 if (empty($pagetypepattern)) { 00642 $pagetypepattern = $this->page->pagetype; 00643 } 00644 00645 $blockinstance = new stdClass; 00646 $blockinstance->blockname = $blockname; 00647 $blockinstance->parentcontextid = $this->page->context->id; 00648 $blockinstance->showinsubcontexts = !empty($showinsubcontexts); 00649 $blockinstance->pagetypepattern = $pagetypepattern; 00650 $blockinstance->subpagepattern = $subpagepattern; 00651 $blockinstance->defaultregion = $region; 00652 $blockinstance->defaultweight = $weight; 00653 $blockinstance->configdata = ''; 00654 $blockinstance->id = $DB->insert_record('block_instances', $blockinstance); 00655 00656 // Ensure the block context is created. 00657 get_context_instance(CONTEXT_BLOCK, $blockinstance->id); 00658 00659 // If the new instance was created, allow it to do additional setup 00660 if ($block = block_instance($blockname, $blockinstance)) { 00661 $block->instance_create(); 00662 } 00663 } 00664 00665 public function add_block_at_end_of_default_region($blockname) { 00666 $defaulregion = $this->get_default_region(); 00667 00668 $lastcurrentblock = end($this->birecordsbyregion[$defaulregion]); 00669 if ($lastcurrentblock) { 00670 $weight = $lastcurrentblock->weight + 1; 00671 } else { 00672 $weight = 0; 00673 } 00674 00675 if ($this->page->subpage) { 00676 $subpage = $this->page->subpage; 00677 } else { 00678 $subpage = null; 00679 } 00680 00681 // Special case. Course view page type include the course format, but we 00682 // want to add the block non-format-specifically. 00683 $pagetypepattern = $this->page->pagetype; 00684 if (strpos($pagetypepattern, 'course-view') === 0) { 00685 $pagetypepattern = 'course-view-*'; 00686 } 00687 00688 // We should end using this for ALL the blocks, making always the 1st option 00689 // the default one to be used. Until then, this is one hack to avoid the 00690 // 'pagetypewarning' message on blocks initial edition (MDL-27829) caused by 00691 // non-existing $pagetypepattern set. This way at least we guarantee one "valid" 00692 // (the FIRST $pagetypepattern will be set) 00693 00694 // We are applying it to all blocks created in mod pages for now and only if the 00695 // default pagetype is not one of the available options 00696 if (preg_match('/^mod-.*-/', $pagetypepattern)) { 00697 $pagetypelist = generate_page_type_patterns($this->page->pagetype, null, $this->page->context); 00698 // Only go for the first if the pagetype is not a valid option 00699 if (is_array($pagetypelist) && !array_key_exists($pagetypepattern, $pagetypelist)) { 00700 $pagetypepattern = key($pagetypelist); 00701 } 00702 } 00703 // Surely other pages like course-report will need this too, they just are not important 00704 // enough now. This will be decided in the coming days. (MDL-27829, MDL-28150) 00705 00706 $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage); 00707 } 00708 00716 public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL, $showinsubcontexts=false, $weight=0) { 00717 $this->add_regions(array_keys($blocks)); 00718 foreach ($blocks as $region => $regionblocks) { 00719 $weight = 0; 00720 foreach ($regionblocks as $blockname) { 00721 $this->add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern, $subpagepattern); 00722 $weight += 1; 00723 } 00724 } 00725 } 00726 00737 public function reposition_block($blockinstanceid, $newregion, $newweight) { 00738 global $DB; 00739 00740 $this->check_region_is_known($newregion); 00741 $inst = $this->find_instance($blockinstanceid); 00742 00743 $bi = $inst->instance; 00744 if ($bi->weight == $bi->defaultweight && $bi->region == $bi->defaultregion && 00745 !$bi->showinsubcontexts && strpos($bi->pagetypepattern, '*') === false && 00746 (!$this->page->subpage || $bi->subpagepattern)) { 00747 00748 // Set default position 00749 $newbi = new stdClass; 00750 $newbi->id = $bi->id; 00751 $newbi->defaultregion = $newregion; 00752 $newbi->defaultweight = $newweight; 00753 $DB->update_record('block_instances', $newbi); 00754 00755 if ($bi->blockpositionid) { 00756 $bp = new stdClass; 00757 $bp->id = $bi->blockpositionid; 00758 $bp->region = $newregion; 00759 $bp->weight = $newweight; 00760 $DB->update_record('block_positions', $bp); 00761 } 00762 00763 } else { 00764 // Just set position on this page. 00765 $bp = new stdClass; 00766 $bp->region = $newregion; 00767 $bp->weight = $newweight; 00768 00769 if ($bi->blockpositionid) { 00770 $bp->id = $bi->blockpositionid; 00771 $DB->update_record('block_positions', $bp); 00772 00773 } else { 00774 $bp->blockinstanceid = $bi->id; 00775 $bp->contextid = $this->page->context->id; 00776 $bp->pagetype = $this->page->pagetype; 00777 if ($this->page->subpage) { 00778 $bp->subpage = $this->page->subpage; 00779 } else { 00780 $bp->subpage = ''; 00781 } 00782 $bp->visible = $bi->visible; 00783 $DB->insert_record('block_positions', $bp); 00784 } 00785 } 00786 } 00787 00794 public function find_instance($instanceid) { 00795 foreach ($this->regions as $region => $notused) { 00796 $this->ensure_instances_exist($region); 00797 foreach($this->blockinstances[$region] as $instance) { 00798 if ($instance->instance->id == $instanceid) { 00799 return $instance; 00800 } 00801 } 00802 } 00803 throw new block_not_on_page_exception($instanceid, $this->page); 00804 } 00805 00807 00813 protected function check_not_yet_loaded() { 00814 if (!is_null($this->birecordsbyregion)) { 00815 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.'); 00816 } 00817 } 00818 00826 protected function check_is_loaded() { 00827 if (is_null($this->birecordsbyregion)) { 00828 throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.'); 00829 } 00830 } 00831 00839 protected function check_known_block_type($blockname, $includeinvisible = false) { 00840 if (!$this->is_known_block_type($blockname, $includeinvisible)) { 00841 if ($this->is_known_block_type($blockname, true)) { 00842 throw new coding_exception('Unknown block type ' . $blockname); 00843 } else { 00844 throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.'); 00845 } 00846 } 00847 } 00848 00855 protected function check_region_is_known($region) { 00856 if (!$this->is_known_region($region)) { 00857 throw new coding_exception('Trying to reference an unknown block region ' . $region); 00858 } 00859 } 00860 00867 protected function prepare_per_region_arrays() { 00868 $result = array(); 00869 foreach ($this->regions as $region => $notused) { 00870 $result[$region] = array(); 00871 } 00872 return $result; 00873 } 00874 00881 protected function create_block_instances($birecords) { 00882 $results = array(); 00883 foreach ($birecords as $record) { 00884 if ($blockobject = block_instance($record->blockname, $record, $this->page)) { 00885 $results[] = $blockobject; 00886 } 00887 } 00888 return $results; 00889 } 00890 00897 public function create_all_block_instances() { 00898 foreach ($this->get_regions() as $region) { 00899 $this->ensure_instances_exist($region); 00900 } 00901 } 00902 00911 protected function create_block_contents($instances, $output, $region) { 00912 $results = array(); 00913 00914 $lastweight = 0; 00915 $lastblock = 0; 00916 if ($this->movingblock) { 00917 $first = reset($instances); 00918 if ($first) { 00919 $lastweight = $first->instance->weight - 2; 00920 } 00921 00922 $strmoveblockhere = get_string('moveblockhere', 'block'); 00923 } 00924 00925 foreach ($instances as $instance) { 00926 $content = $instance->get_content_for_output($output); 00927 if (empty($content)) { 00928 continue; 00929 } 00930 00931 if ($this->movingblock && $lastweight != $instance->instance->weight && 00932 $content->blockinstanceid != $this->movingblock && $lastblock != $this->movingblock) { 00933 $results[] = new block_move_target($strmoveblockhere, $this->get_move_target_url($region, ($lastweight + $instance->instance->weight)/2)); 00934 } 00935 00936 if ($content->blockinstanceid == $this->movingblock) { 00937 $content->add_class('beingmoved'); 00938 $content->annotation .= get_string('movingthisblockcancel', 'block', 00939 html_writer::link($this->page->url, get_string('cancel'))); 00940 } 00941 00942 $results[] = $content; 00943 $lastweight = $instance->instance->weight; 00944 $lastblock = $instance->instance->id; 00945 } 00946 00947 if ($this->movingblock && $lastblock != $this->movingblock) { 00948 $results[] = new block_move_target($strmoveblockhere, $this->get_move_target_url($region, $lastweight + 1)); 00949 } 00950 return $results; 00951 } 00952 00958 protected function ensure_instances_exist($region) { 00959 $this->check_region_is_known($region); 00960 if (!array_key_exists($region, $this->blockinstances)) { 00961 $this->blockinstances[$region] = 00962 $this->create_block_instances($this->birecordsbyregion[$region]); 00963 } 00964 } 00965 00971 protected function ensure_content_created($region, $output) { 00972 $this->ensure_instances_exist($region); 00973 if (!array_key_exists($region, $this->visibleblockcontent)) { 00974 $contents = array(); 00975 if (array_key_exists($region, $this->extracontent)) { 00976 $contents = $this->extracontent[$region]; 00977 } 00978 $contents = array_merge($contents, $this->create_block_contents($this->blockinstances[$region], $output, $region)); 00979 if ($region == $this->defaultregion) { 00980 $addblockui = block_add_block_ui($this->page, $output); 00981 if ($addblockui) { 00982 $contents[] = $addblockui; 00983 } 00984 } 00985 $this->visibleblockcontent[$region] = $contents; 00986 } 00987 } 00988 00990 00998 public function edit_controls($block) { 00999 global $CFG; 01000 01001 if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) { 01002 $undeletableblocktypes = array('navigation','settings'); 01003 } else if (is_string($CFG->undeletableblocktypes)) { 01004 $undeletableblocktypes = explode(',', $CFG->undeletableblocktypes); 01005 } else { 01006 $undeletableblocktypes = $CFG->undeletableblocktypes; 01007 } 01008 01009 $controls = array(); 01010 $actionurl = $this->page->url->out(false, array('sesskey'=> sesskey())); 01011 01012 if ($this->page->user_can_edit_blocks()) { 01013 // Move icon. 01014 $controls[] = array('url' => $actionurl . '&bui_moveid=' . $block->instance->id, 01015 'icon' => 't/move', 'caption' => get_string('move')); 01016 } 01017 01018 if ($this->page->user_can_edit_blocks() || $block->user_can_edit()) { 01019 // Edit config icon - always show - needed for positioning UI. 01020 $controls[] = array('url' => $actionurl . '&bui_editid=' . $block->instance->id, 01021 'icon' => 't/edit', 'caption' => get_string('configuration')); 01022 } 01023 01024 if ($this->page->user_can_edit_blocks() && $block->user_can_edit() && $block->user_can_addto($this->page)) { 01025 if (!in_array($block->instance->blockname, $undeletableblocktypes) 01026 || !in_array($block->instance->pagetypepattern, array('*', 'site-index')) 01027 || $block->instance->parentcontextid != SITEID) { 01028 // Delete icon. 01029 $controls[] = array('url' => $actionurl . '&bui_deleteid=' . $block->instance->id, 01030 'icon' => 't/delete', 'caption' => get_string('delete')); 01031 } 01032 } 01033 01034 if ($this->page->user_can_edit_blocks() && $block->instance_can_be_hidden()) { 01035 // Show/hide icon. 01036 if ($block->instance->visible) { 01037 $controls[] = array('url' => $actionurl . '&bui_hideid=' . $block->instance->id, 01038 'icon' => 't/hide', 'caption' => get_string('hide')); 01039 } else { 01040 $controls[] = array('url' => $actionurl . '&bui_showid=' . $block->instance->id, 01041 'icon' => 't/show', 'caption' => get_string('show')); 01042 } 01043 } 01044 01045 // Assign roles icon. 01046 if (has_capability('moodle/role:assign', $block->context)) { 01047 //TODO: please note it is sloppy to pass urls through page parameters!! 01048 // it is shortened because some web servers (e.g. IIS by default) give 01049 // a 'security' error if you try to pass a full URL as a GET parameter in another URL. 01050 $return = $this->page->url->out(false); 01051 $return = str_replace($CFG->wwwroot . '/', '', $return); 01052 01053 $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin . 01054 '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return), 01055 'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role')); 01056 } 01057 01058 return $controls; 01059 } 01060 01066 public function process_url_actions() { 01067 if (!$this->page->user_is_editing()) { 01068 return false; 01069 } 01070 return $this->process_url_add() || $this->process_url_delete() || 01071 $this->process_url_show_hide() || $this->process_url_edit() || 01072 $this->process_url_move(); 01073 } 01074 01079 public function process_url_add() { 01080 $blocktype = optional_param('bui_addblock', null, PARAM_PLUGIN); 01081 if (!$blocktype) { 01082 return false; 01083 } 01084 01085 require_sesskey(); 01086 01087 if (!$this->page->user_can_edit_blocks()) { 01088 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('addblock')); 01089 } 01090 01091 if (!array_key_exists($blocktype, $this->get_addable_blocks())) { 01092 throw new moodle_exception('cannotaddthisblocktype', '', $this->page->url->out(), $blocktype); 01093 } 01094 01095 $this->add_block_at_end_of_default_region($blocktype); 01096 01097 // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there. 01098 $this->page->ensure_param_not_in_url('bui_addblock'); 01099 01100 return true; 01101 } 01102 01107 public function process_url_delete() { 01108 $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER); 01109 if (!$blockid) { 01110 return false; 01111 } 01112 01113 require_sesskey(); 01114 01115 $block = $this->page->blocks->find_instance($blockid); 01116 01117 if (!$block->user_can_edit() || !$this->page->user_can_edit_blocks() || !$block->user_can_addto($this->page)) { 01118 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('deleteablock')); 01119 } 01120 01121 blocks_delete_instance($block->instance); 01122 01123 // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there. 01124 $this->page->ensure_param_not_in_url('bui_deleteid'); 01125 01126 return true; 01127 } 01128 01133 public function process_url_show_hide() { 01134 if ($blockid = optional_param('bui_hideid', null, PARAM_INTEGER)) { 01135 $newvisibility = 0; 01136 } else if ($blockid = optional_param('bui_showid', null, PARAM_INTEGER)) { 01137 $newvisibility = 1; 01138 } else { 01139 return false; 01140 } 01141 01142 require_sesskey(); 01143 01144 $block = $this->page->blocks->find_instance($blockid); 01145 01146 if (!$this->page->user_can_edit_blocks()) { 01147 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('hideshowblocks')); 01148 } else if (!$block->instance_can_be_hidden()) { 01149 return false; 01150 } 01151 01152 blocks_set_visibility($block->instance, $this->page, $newvisibility); 01153 01154 // If the page URL was a guses, it will contain the bui_... param, so we must make sure it is not there. 01155 $this->page->ensure_param_not_in_url('bui_hideid'); 01156 $this->page->ensure_param_not_in_url('bui_showid'); 01157 01158 return true; 01159 } 01160 01166 public function process_url_edit() { 01167 global $CFG, $DB, $PAGE, $OUTPUT; 01168 01169 $blockid = optional_param('bui_editid', null, PARAM_INTEGER); 01170 if (!$blockid) { 01171 return false; 01172 } 01173 01174 require_sesskey(); 01175 require_once($CFG->dirroot . '/blocks/edit_form.php'); 01176 01177 $block = $this->find_instance($blockid); 01178 01179 if (!$block->user_can_edit() && !$this->page->user_can_edit_blocks()) { 01180 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock')); 01181 } 01182 01183 $editpage = new moodle_page(); 01184 $editpage->set_pagelayout('admin'); 01185 $editpage->set_course($this->page->course); 01186 //$editpage->set_context($block->context); 01187 $editpage->set_context($this->page->context); 01188 if ($this->page->cm) { 01189 $editpage->set_cm($this->page->cm); 01190 } 01191 $editurlbase = str_replace($CFG->wwwroot . '/', '/', $this->page->url->out_omit_querystring()); 01192 $editurlparams = $this->page->url->params(); 01193 $editurlparams['bui_editid'] = $blockid; 01194 $editpage->set_url($editurlbase, $editurlparams); 01195 $editpage->set_block_actions_done(); 01196 // At this point we are either going to redirect, or display the form, so 01197 // overwrite global $PAGE ready for this. (Formslib refers to it.) 01198 $PAGE = $editpage; 01199 //some functions like MoodleQuickForm::addHelpButton use $OUTPUT so we need to replace that to 01200 $output = $editpage->get_renderer('core'); 01201 $OUTPUT = $output; 01202 01203 $formfile = $CFG->dirroot . '/blocks/' . $block->name() . '/edit_form.php'; 01204 if (is_readable($formfile)) { 01205 require_once($formfile); 01206 $classname = 'block_' . $block->name() . '_edit_form'; 01207 if (!class_exists($classname)) { 01208 $classname = 'block_edit_form'; 01209 } 01210 } else { 01211 $classname = 'block_edit_form'; 01212 } 01213 01214 $mform = new $classname($editpage->url, $block, $this->page); 01215 $mform->set_data($block->instance); 01216 01217 if ($mform->is_cancelled()) { 01218 redirect($this->page->url); 01219 01220 } else if ($data = $mform->get_data()) { 01221 $bi = new stdClass; 01222 $bi->id = $block->instance->id; 01223 $bi->pagetypepattern = $data->bui_pagetypepattern; 01224 if (empty($data->bui_subpagepattern) || $data->bui_subpagepattern == '%@NULL@%') { 01225 $bi->subpagepattern = null; 01226 } else { 01227 $bi->subpagepattern = $data->bui_subpagepattern; 01228 } 01229 01230 $systemcontext = get_context_instance(CONTEXT_SYSTEM); 01231 $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID); 01232 $parentcontext = get_context_instance_by_id($data->bui_parentcontextid); 01233 01234 // Updating stickiness and contexts. See MDL-21375 for details. 01235 if (has_capability('moodle/site:manageblocks', $parentcontext)) { // Check permissions in destination 01236 01237 // Explicitly set the default context 01238 $bi->parentcontextid = $parentcontext->id; 01239 01240 if ($data->bui_editingatfrontpage) { // The block is being edited on the front page 01241 01242 // The interface here is a special case because the pagetype pattern is 01243 // totally derived from the context menu. Here are the excpetions. MDL-30340 01244 01245 switch ($data->bui_contexts) { 01246 case BUI_CONTEXTS_ENTIRE_SITE: 01247 // The user wants to show the block across the entire site 01248 $bi->parentcontextid = $systemcontext->id; 01249 $bi->showinsubcontexts = true; 01250 $bi->pagetypepattern = '*'; 01251 break; 01252 case BUI_CONTEXTS_FRONTPAGE_SUBS: 01253 // The user wants the block shown on the front page and all subcontexts 01254 $bi->parentcontextid = $frontpagecontext->id; 01255 $bi->showinsubcontexts = true; 01256 $bi->pagetypepattern = '*'; 01257 break; 01258 case BUI_CONTEXTS_FRONTPAGE_ONLY: 01259 // The user want to show the front page on the frontpage only 01260 $bi->parentcontextid = $frontpagecontext->id; 01261 $bi->showinsubcontexts = false; 01262 $bi->pagetypepattern = 'site-index'; 01263 // This is the only relevant page type anyway but we'll set it explicitly just 01264 // in case the front page grows site-index-* subpages of its own later 01265 break; 01266 } 01267 } 01268 } 01269 01270 $bits = explode('-', $bi->pagetypepattern); 01271 // hacks for some contexts 01272 if (($parentcontext->contextlevel == CONTEXT_COURSE) && ($parentcontext->instanceid != SITEID)) { 01273 // For course context 01274 // is page type pattern is mod-*, change showinsubcontext to 1 01275 if ($bits[0] == 'mod' || $bi->pagetypepattern == '*') { 01276 $bi->showinsubcontexts = 1; 01277 } else { 01278 $bi->showinsubcontexts = 0; 01279 } 01280 } else if ($parentcontext->contextlevel == CONTEXT_USER) { 01281 // for user context 01282 // subpagepattern should be null 01283 if ($bits[0] == 'user' or $bits[0] == 'my') { 01284 // we don't need subpagepattern in usercontext 01285 $bi->subpagepattern = null; 01286 } 01287 } 01288 01289 $bi->defaultregion = $data->bui_defaultregion; 01290 $bi->defaultweight = $data->bui_defaultweight; 01291 $DB->update_record('block_instances', $bi); 01292 01293 if (!empty($block->config)) { 01294 $config = clone($block->config); 01295 } else { 01296 $config = new stdClass; 01297 } 01298 foreach ($data as $configfield => $value) { 01299 if (strpos($configfield, 'config_') !== 0) { 01300 continue; 01301 } 01302 $field = substr($configfield, 7); 01303 $config->$field = $value; 01304 } 01305 $block->instance_config_save($config); 01306 01307 $bp = new stdClass; 01308 $bp->visible = $data->bui_visible; 01309 $bp->region = $data->bui_region; 01310 $bp->weight = $data->bui_weight; 01311 $needbprecord = !$data->bui_visible || $data->bui_region != $data->bui_defaultregion || 01312 $data->bui_weight != $data->bui_defaultweight; 01313 01314 if ($block->instance->blockpositionid && !$needbprecord) { 01315 $DB->delete_records('block_positions', array('id' => $block->instance->blockpositionid)); 01316 01317 } else if ($block->instance->blockpositionid && $needbprecord) { 01318 $bp->id = $block->instance->blockpositionid; 01319 $DB->update_record('block_positions', $bp); 01320 01321 } else if ($needbprecord) { 01322 $bp->blockinstanceid = $block->instance->id; 01323 $bp->contextid = $this->page->context->id; 01324 $bp->pagetype = $this->page->pagetype; 01325 if ($this->page->subpage) { 01326 $bp->subpage = $this->page->subpage; 01327 } else { 01328 $bp->subpage = ''; 01329 } 01330 $DB->insert_record('block_positions', $bp); 01331 } 01332 01333 redirect($this->page->url); 01334 01335 } else { 01336 $strheading = get_string('blockconfiga', 'moodle', $block->get_title()); 01337 $editpage->set_title($strheading); 01338 $editpage->set_heading($strheading); 01339 $bits = explode('-', $this->page->pagetype); 01340 if ($bits[0] == 'tag' && !empty($this->page->subpage)) { 01341 // better navbar for tag pages 01342 $editpage->navbar->add(get_string('tags'), new moodle_url('/tag/')); 01343 $tag = tag_get('id', $this->page->subpage, '*'); 01344 // tag search page doesn't have subpageid 01345 if ($tag) { 01346 $editpage->navbar->add($tag->name, new moodle_url('/tag/index.php', array('id'=>$tag->id))); 01347 } 01348 } 01349 $editpage->navbar->add($block->get_title()); 01350 $editpage->navbar->add(get_string('configuration')); 01351 echo $output->header(); 01352 echo $output->heading($strheading, 2); 01353 $mform->display(); 01354 echo $output->footer(); 01355 exit; 01356 } 01357 } 01358 01364 public function process_url_move() { 01365 global $CFG, $DB, $PAGE; 01366 01367 $blockid = optional_param('bui_moveid', null, PARAM_INTEGER); 01368 if (!$blockid) { 01369 return false; 01370 } 01371 01372 require_sesskey(); 01373 01374 $block = $this->find_instance($blockid); 01375 01376 if (!$this->page->user_can_edit_blocks()) { 01377 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock')); 01378 } 01379 01380 $newregion = optional_param('bui_newregion', '', PARAM_ALPHANUMEXT); 01381 $newweight = optional_param('bui_newweight', null, PARAM_FLOAT); 01382 if (!$newregion || is_null($newweight)) { 01383 // Don't have a valid target position yet, must be just starting the move. 01384 $this->movingblock = $blockid; 01385 $this->page->ensure_param_not_in_url('bui_moveid'); 01386 return false; 01387 } 01388 01389 if (!$this->is_known_region($newregion)) { 01390 throw new moodle_exception('unknownblockregion', '', $this->page->url, $newregion); 01391 } 01392 01393 // Move this block. This may involve moving other nearby blocks. 01394 $blocks = $this->birecordsbyregion[$newregion]; 01395 01396 $maxweight = self::MAX_WEIGHT; 01397 $minweight = -self::MAX_WEIGHT; 01398 01399 // Initialise the used weights and spareweights array with the default values 01400 $spareweights = array(); 01401 $usedweights = array(); 01402 for ($i = $minweight; $i <= $maxweight; $i++) { 01403 $spareweights[$i] = $i; 01404 $usedweights[$i] = array(); 01405 } 01406 01407 // Check each block and sort out where we have used weights 01408 foreach ($blocks as $bi) { 01409 if ($bi->weight > $maxweight) { 01410 // If this statement is true then the blocks weight is more than the 01411 // current maximum. To ensure that we can get the best block position 01412 // we will initialise elements within the usedweights and spareweights 01413 // arrays between the blocks weight (which will then be the new max) and 01414 // the current max 01415 $parseweight = $bi->weight; 01416 while (!array_key_exists($parseweight, $usedweights)) { 01417 $usedweights[$parseweight] = array(); 01418 $spareweights[$parseweight] = $parseweight; 01419 $parseweight--; 01420 } 01421 $maxweight = $bi->weight; 01422 } else if ($bi->weight < $minweight) { 01423 // As above except this time the blocks weight is LESS than the 01424 // the current minimum, so we will initialise the array from the 01425 // blocks weight (new minimum) to the current minimum 01426 $parseweight = $bi->weight; 01427 while (!array_key_exists($parseweight, $usedweights)) { 01428 $usedweights[$parseweight] = array(); 01429 $spareweights[$parseweight] = $parseweight; 01430 $parseweight++; 01431 } 01432 $minweight = $bi->weight; 01433 } 01434 if ($bi->id != $block->instance->id) { 01435 unset($spareweights[$bi->weight]); 01436 $usedweights[$bi->weight][] = $bi->id; 01437 } 01438 } 01439 01440 // First we find the nearest gap in the list of weights. 01441 $bestdistance = max(abs($newweight - self::MAX_WEIGHT), abs($newweight + self::MAX_WEIGHT)) + 1; 01442 $bestgap = null; 01443 foreach ($spareweights as $spareweight) { 01444 if (abs($newweight - $spareweight) < $bestdistance) { 01445 $bestdistance = abs($newweight - $spareweight); 01446 $bestgap = $spareweight; 01447 } 01448 } 01449 01450 // If there is no gap, we have to go outside -self::MAX_WEIGHT .. self::MAX_WEIGHT. 01451 if (is_null($bestgap)) { 01452 $bestgap = self::MAX_WEIGHT + 1; 01453 while (!empty($usedweights[$bestgap])) { 01454 $bestgap++; 01455 } 01456 } 01457 01458 // Now we know the gap we are aiming for, so move all the blocks along. 01459 if ($bestgap < $newweight) { 01460 $newweight = floor($newweight); 01461 for ($weight = $bestgap + 1; $weight <= $newweight; $weight++) { 01462 foreach ($usedweights[$weight] as $biid) { 01463 $this->reposition_block($biid, $newregion, $weight - 1); 01464 } 01465 } 01466 $this->reposition_block($block->instance->id, $newregion, $newweight); 01467 } else { 01468 $newweight = ceil($newweight); 01469 for ($weight = $bestgap - 1; $weight >= $newweight; $weight--) { 01470 if (array_key_exists($weight, $usedweights)) { 01471 foreach ($usedweights[$weight] as $biid) { 01472 $this->reposition_block($biid, $newregion, $weight + 1); 01473 } 01474 } 01475 } 01476 $this->reposition_block($block->instance->id, $newregion, $newweight); 01477 } 01478 01479 $this->page->ensure_param_not_in_url('bui_moveid'); 01480 $this->page->ensure_param_not_in_url('bui_newregion'); 01481 $this->page->ensure_param_not_in_url('bui_newweight'); 01482 return true; 01483 } 01484 01490 public function show_only_fake_blocks($setting = true) { 01491 $this->fakeblocksonly = $setting; 01492 } 01493 } 01494 01496 01505 function block_method_result($blockname, $method, $param = NULL) { 01506 if(!block_load_class($blockname)) { 01507 return NULL; 01508 } 01509 return call_user_func(array('block_'.$blockname, $method), $param); 01510 } 01511 01520 function block_instance($blockname, $instance = NULL, $page = NULL) { 01521 if(!block_load_class($blockname)) { 01522 return false; 01523 } 01524 $classname = 'block_'.$blockname; 01525 $retval = new $classname; 01526 if($instance !== NULL) { 01527 if (is_null($page)) { 01528 global $PAGE; 01529 $page = $PAGE; 01530 } 01531 $retval->_load_instance($instance, $page); 01532 } 01533 return $retval; 01534 } 01535 01542 function block_load_class($blockname) { 01543 global $CFG; 01544 01545 if(empty($blockname)) { 01546 return false; 01547 } 01548 01549 $classname = 'block_'.$blockname; 01550 01551 if(class_exists($classname)) { 01552 return true; 01553 } 01554 01555 $blockpath = $CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'; 01556 01557 if (file_exists($blockpath)) { 01558 require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); 01559 include_once($blockpath); 01560 }else{ 01561 //debugging("$blockname code does not exist in $blockpath", DEBUG_DEVELOPER); 01562 return false; 01563 } 01564 01565 return class_exists($classname); 01566 } 01567 01575 function matching_page_type_patterns($pagetype) { 01576 $patterns = array($pagetype); 01577 $bits = explode('-', $pagetype); 01578 if (count($bits) == 3 && $bits[0] == 'mod') { 01579 if ($bits[2] == 'view') { 01580 $patterns[] = 'mod-*-view'; 01581 } else if ($bits[2] == 'index') { 01582 $patterns[] = 'mod-*-index'; 01583 } 01584 } 01585 while (count($bits) > 0) { 01586 $patterns[] = implode('-', $bits) . '-*'; 01587 array_pop($bits); 01588 } 01589 $patterns[] = '*'; 01590 return $patterns; 01591 } 01592 01602 function generate_page_type_patterns($pagetype, $parentcontext = null, $currentcontext = null) { 01603 global $CFG; 01604 01605 $bits = explode('-', $pagetype); 01606 01607 $core = get_core_subsystems(); 01608 $plugins = get_plugin_types(); 01609 01610 //progressively strip pieces off the page type looking for a match 01611 $componentarray = null; 01612 for ($i = count($bits); $i > 0; $i--) { 01613 $possiblecomponentarray = array_slice($bits, 0, $i); 01614 $possiblecomponent = implode('', $possiblecomponentarray); 01615 01616 // Check to see if the component is a core component 01617 if (array_key_exists($possiblecomponent, $core) && !empty($core[$possiblecomponent])) { 01618 $libfile = $CFG->dirroot.'/'.$core[$possiblecomponent].'/lib.php'; 01619 if (file_exists($libfile)) { 01620 require_once($libfile); 01621 $function = $possiblecomponent.'_page_type_list'; 01622 if (function_exists($function)) { 01623 if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { 01624 break; 01625 } 01626 } 01627 } 01628 } 01629 01630 //check the plugin directory and look for a callback 01631 if (array_key_exists($possiblecomponent, $plugins) && !empty($plugins[$possiblecomponent])) { 01632 01633 //We've found a plugin type. Look for a plugin name by getting the next section of page type 01634 if (count($bits) > $i) { 01635 $pluginname = $bits[$i]; 01636 $directory = get_plugin_directory($possiblecomponent, $pluginname); 01637 if (!empty($directory)){ 01638 $libfile = $directory.'/lib.php'; 01639 if (file_exists($libfile)) { 01640 require_once($libfile); 01641 $function = $possiblecomponent.'_'.$pluginname.'_page_type_list'; 01642 if (!function_exists($function)) { 01643 $function = $pluginname.'_page_type_list'; 01644 } 01645 if (function_exists($function)) { 01646 if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { 01647 break; 01648 } 01649 } 01650 } 01651 } 01652 } 01653 01654 //we'll only get to here if we still don't have any patterns 01655 //the plugin type may have a callback 01656 $directory = get_plugin_directory($possiblecomponent, null); 01657 if (!empty($directory)){ 01658 $libfile = $directory.'/lib.php'; 01659 if (file_exists($libfile)) { 01660 require_once($libfile); 01661 $function = $possiblecomponent.'_page_type_list'; 01662 if (function_exists($function)) { 01663 if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { 01664 break; 01665 } 01666 } 01667 } 01668 } 01669 } 01670 } 01671 01672 if (empty($patterns)) { 01673 $patterns = default_page_type_list($pagetype, $parentcontext, $currentcontext); 01674 } 01675 01676 // Ensure that the * pattern is always available if editing block 'at distance', so 01677 // we always can 'bring back' it to the original context. MDL-30340 01678 if ((!isset($currentcontext) or !isset($parentcontext) or $currentcontext->id != $parentcontext->id) && !isset($patterns['*'])) { 01679 // TODO: We could change the string here, showing its 'bring back' meaning 01680 $patterns['*'] = get_string('page-x', 'pagetype'); 01681 } 01682 01683 return $patterns; 01684 } 01685 01694 function default_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) { 01695 // Generate page type patterns based on current page type if 01696 // callbacks haven't been defined 01697 $patterns = array($pagetype => $pagetype); 01698 $bits = explode('-', $pagetype); 01699 while (count($bits) > 0) { 01700 $pattern = implode('-', $bits) . '-*'; 01701 $pagetypestringname = 'page-'.str_replace('*', 'x', $pattern); 01702 // guessing page type description 01703 if (get_string_manager()->string_exists($pagetypestringname, 'pagetype')) { 01704 $patterns[$pattern] = get_string($pagetypestringname, 'pagetype'); 01705 } else { 01706 $patterns[$pattern] = $pattern; 01707 } 01708 array_pop($bits); 01709 } 01710 $patterns['*'] = get_string('page-x', 'pagetype'); 01711 return $patterns; 01712 } 01713 01722 function my_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) { 01723 return array('my-index' => get_string('page-my-index', 'pagetype')); 01724 } 01725 01735 function mod_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) { 01736 $patterns = plugin_page_type_list($pagetype, $parentcontext, $currentcontext); 01737 if (empty($patterns)) { 01738 // if modules don't have callbacks 01739 // generate two default page type patterns for modules only 01740 $bits = explode('-', $pagetype); 01741 $patterns = array($pagetype => $pagetype); 01742 if ($bits[2] == 'view') { 01743 $patterns['mod-*-view'] = get_string('page-mod-x-view', 'pagetype'); 01744 } else if ($bits[2] == 'index') { 01745 $patterns['mod-*-index'] = get_string('page-mod-x-index', 'pagetype'); 01746 } 01747 } 01748 return $patterns; 01749 } 01751 01759 function block_add_block_ui($page, $output) { 01760 global $CFG, $OUTPUT; 01761 if (!$page->user_is_editing() || !$page->user_can_edit_blocks()) { 01762 return null; 01763 } 01764 01765 $bc = new block_contents(); 01766 $bc->title = get_string('addblock'); 01767 $bc->add_class('block_adminblock'); 01768 01769 $missingblocks = $page->blocks->get_addable_blocks(); 01770 if (empty($missingblocks)) { 01771 $bc->content = get_string('noblockstoaddhere'); 01772 return $bc; 01773 } 01774 01775 $menu = array(); 01776 foreach ($missingblocks as $block) { 01777 $blockobject = block_instance($block->name); 01778 if ($blockobject !== false && $blockobject->user_can_addto($page)) { 01779 $menu[$block->name] = $blockobject->get_title(); 01780 } 01781 } 01782 collatorlib::asort($menu); 01783 01784 $actionurl = new moodle_url($page->url, array('sesskey'=>sesskey())); 01785 $select = new single_select($actionurl, 'bui_addblock', $menu, null, array(''=>get_string('adddots')), 'add_block'); 01786 $bc->content = $OUTPUT->render($select); 01787 return $bc; 01788 } 01789 01790 // Functions that have been deprecated by block_manager ======================= 01791 01802 function blocks_get_missing(&$page, &$blockmanager) { 01803 debugging('blocks_get_missing is deprecated. Please use $page->blocks->get_addable_blocks() instead.', DEBUG_DEVELOPER); 01804 $blocks = $page->blocks->get_addable_blocks(); 01805 $ids = array(); 01806 foreach ($blocks as $block) { 01807 $ids[] = $block->id; 01808 } 01809 return $ids; 01810 } 01811 01819 function blocks_remove_inappropriate($course) { 01820 // TODO 01821 return; 01822 /* 01823 $blockmanager = blocks_get_by_page($page); 01824 01825 if (empty($blockmanager)) { 01826 return; 01827 } 01828 01829 if (($pageformat = $page->pagetype) == NULL) { 01830 return; 01831 } 01832 01833 foreach($blockmanager as $region) { 01834 foreach($region as $instance) { 01835 $block = blocks_get_record($instance->blockid); 01836 if(!blocks_name_allowed_in_format($block->name, $pageformat)) { 01837 blocks_delete_instance($instance->instance); 01838 } 01839 } 01840 }*/ 01841 } 01842 01850 function blocks_name_allowed_in_format($name, $pageformat) { 01851 $accept = NULL; 01852 $maxdepth = -1; 01853 $formats = block_method_result($name, 'applicable_formats'); 01854 if (!$formats) { 01855 $formats = array(); 01856 } 01857 foreach ($formats as $format => $allowed) { 01858 $formatregex = '/^'.str_replace('*', '[^-]*', $format).'.*$/'; 01859 $depth = substr_count($format, '-'); 01860 if (preg_match($formatregex, $pageformat) && $depth > $maxdepth) { 01861 $maxdepth = $depth; 01862 $accept = $allowed; 01863 } 01864 } 01865 if ($accept === NULL) { 01866 $accept = !empty($formats['all']); 01867 } 01868 return $accept; 01869 } 01870 01878 function blocks_delete_instance($instance, $nolongerused = false, $skipblockstables = false) { 01879 global $DB; 01880 01881 if ($block = block_instance($instance->blockname, $instance)) { 01882 $block->instance_delete(); 01883 } 01884 delete_context(CONTEXT_BLOCK, $instance->id); 01885 01886 if (!$skipblockstables) { 01887 $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id)); 01888 $DB->delete_records('block_instances', array('id' => $instance->id)); 01889 $DB->delete_records_list('user_preferences', 'name', array('block'.$instance->id.'hidden','docked_block_instance_'.$instance->id)); 01890 } 01891 } 01892 01898 function blocks_delete_all_for_context($contextid) { 01899 global $DB; 01900 $instances = $DB->get_recordset('block_instances', array('parentcontextid' => $contextid)); 01901 foreach ($instances as $instance) { 01902 blocks_delete_instance($instance, true); 01903 } 01904 $instances->close(); 01905 $DB->delete_records('block_instances', array('parentcontextid' => $contextid)); 01906 $DB->delete_records('block_positions', array('contextid' => $contextid)); 01907 } 01908 01917 function blocks_set_visibility($instance, $page, $newvisibility) { 01918 global $DB; 01919 if (!empty($instance->blockpositionid)) { 01920 // Already have local information on this page. 01921 $DB->set_field('block_positions', 'visible', $newvisibility, array('id' => $instance->blockpositionid)); 01922 return; 01923 } 01924 01925 // Create a new block_positions record. 01926 $bp = new stdClass; 01927 $bp->blockinstanceid = $instance->id; 01928 $bp->contextid = $page->context->id; 01929 $bp->pagetype = $page->pagetype; 01930 if ($page->subpage) { 01931 $bp->subpage = $page->subpage; 01932 } 01933 $bp->visible = $newvisibility; 01934 $bp->region = $instance->defaultregion; 01935 $bp->weight = $instance->defaultweight; 01936 $DB->insert_record('block_positions', $bp); 01937 } 01938 01947 function blocks_delete_all_on_page($pagetype, $pageid) { 01948 global $DB; 01949 01950 debugging('Call to deprecated function blocks_delete_all_on_page. ' . 01951 'This function cannot work any more. Doing nothing. ' . 01952 'Please update your code to use a block_manager method $PAGE->blocks->....', DEBUG_DEVELOPER); 01953 return false; 01954 } 01955 01965 function blocks_repopulate_page($page) { 01966 global $CFG; 01967 01968 debugging('Call to deprecated function blocks_repopulate_page. ' . 01969 'Use a more specific method like blocks_add_default_course_blocks, ' . 01970 'or just call $PAGE->blocks->add_blocks()', DEBUG_DEVELOPER); 01971 01973 if (!empty($CFG->defaultblocks_override)) { 01974 $blocknames = $CFG->defaultblocks_override; 01975 } else { 01976 $blocknames = $page->blocks_get_default(); 01977 } 01978 01979 $blocks = blocks_parse_default_blocks_list($blocknames); 01980 $page->blocks->add_blocks($blocks); 01981 01982 return true; 01983 } 01984 01992 function blocks_get_record($blockid = NULL, $notusedanymore = false) { 01993 global $PAGE; 01994 $blocks = $PAGE->blocks->get_installed_blocks(); 01995 if ($blockid === NULL) { 01996 return $blocks; 01997 } else if (isset($blocks[$blockid])) { 01998 return $blocks[$blockid]; 01999 } else { 02000 return false; 02001 } 02002 } 02003 02011 function blocks_find_block($blockid, $blocksarray) { 02012 if (empty($blocksarray)) { 02013 return false; 02014 } 02015 foreach($blocksarray as $blockgroup) { 02016 if (empty($blockgroup)) { 02017 continue; 02018 } 02019 foreach($blockgroup as $instance) { 02020 if($instance->blockid == $blockid) { 02021 return $instance; 02022 } 02023 } 02024 } 02025 return false; 02026 } 02027 02028 // Functions for programatically adding default blocks to pages ================ 02029 02036 function blocks_parse_default_blocks_list($blocksstr) { 02037 $blocks = array(); 02038 $bits = explode(':', $blocksstr); 02039 if (!empty($bits)) { 02040 $leftbits = trim(array_shift($bits)); 02041 if ($leftbits != '') { 02042 $blocks[BLOCK_POS_LEFT] = explode(',', $leftbits); 02043 } 02044 } 02045 if (!empty($bits)) { 02046 $rightbits =trim(array_shift($bits)); 02047 if ($rightbits != '') { 02048 $blocks[BLOCK_POS_RIGHT] = explode(',', $rightbits); 02049 } 02050 } 02051 return $blocks; 02052 } 02053 02057 function blocks_get_default_site_course_blocks() { 02058 global $CFG; 02059 02060 if (!empty($CFG->defaultblocks_site)) { 02061 return blocks_parse_default_blocks_list($CFG->defaultblocks_site); 02062 } else { 02063 return array( 02064 BLOCK_POS_LEFT => array('site_main_menu'), 02065 BLOCK_POS_RIGHT => array('course_summary', 'calendar_month') 02066 ); 02067 } 02068 } 02069 02075 function blocks_add_default_course_blocks($course) { 02076 global $CFG; 02077 02078 if (!empty($CFG->defaultblocks_override)) { 02079 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks_override); 02080 02081 } else if ($course->id == SITEID) { 02082 $blocknames = blocks_get_default_site_course_blocks(); 02083 02084 } else { 02085 $defaultblocks = 'defaultblocks_' . $course->format; 02086 if (!empty($CFG->$defaultblocks)) { 02087 $blocknames = blocks_parse_default_blocks_list($CFG->$defaultblocks); 02088 02089 } else { 02090 $formatconfig = $CFG->dirroot.'/course/format/'.$course->format.'/config.php'; 02091 $format = array(); // initialize array in external file 02092 if (is_readable($formatconfig)) { 02093 include($formatconfig); 02094 } 02095 if (!empty($format['defaultblocks'])) { 02096 $blocknames = blocks_parse_default_blocks_list($format['defaultblocks']); 02097 02098 } else if (!empty($CFG->defaultblocks)){ 02099 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks); 02100 02101 } else { 02102 $blocknames = array( 02103 BLOCK_POS_LEFT => array(), 02104 BLOCK_POS_RIGHT => array('search_forums', 'news_items', 'calendar_upcoming', 'recent_activity') 02105 ); 02106 } 02107 } 02108 } 02109 02110 if ($course->id == SITEID) { 02111 $pagetypepattern = 'site-index'; 02112 } else { 02113 $pagetypepattern = 'course-view-*'; 02114 } 02115 $page = new moodle_page(); 02116 $page->set_course($course); 02117 $page->blocks->add_blocks($blocknames, $pagetypepattern); 02118 } 02119 02123 function blocks_add_default_system_blocks() { 02124 global $DB; 02125 02126 $page = new moodle_page(); 02127 $page->set_context(get_context_instance(CONTEXT_SYSTEM)); 02128 $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('navigation', 'settings')), '*', null, true); 02129 $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2); 02130 02131 if ($defaultmypage = $DB->get_record('my_pages', array('userid'=>null, 'name'=>'__default', 'private'=>1))) { 02132 $subpagepattern = $defaultmypage->id; 02133 } else { 02134 $subpagepattern = null; 02135 } 02136 02137 $page->blocks->add_blocks(array(BLOCK_POS_RIGHT => array('private_files', 'online_users'), 'content' => array('course_overview')), 'my-index', $subpagepattern, false); 02138 }