Merge branch 'MDL-57232-master' of git://github.com/damyon/moodle

This commit is contained in:
David Monllao 2016-12-02 14:20:17 +08:00
commit 76e337ab96
6 changed files with 124 additions and 51 deletions

View File

@ -4,6 +4,7 @@
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/blocklib.php');
require_once($CFG->libdir.'/tablelib.php');
admin_externalpage_setup('manageblocks');
@ -49,36 +50,18 @@
admin_get_root(true, false); // settings not required - only pages
}
if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) {
$undeletableblocktypes = array('navigation', 'settings');
} else if (is_string($CFG->undeletableblocktypes)) {
$undeletableblocktypes = explode(',', $CFG->undeletableblocktypes);
} else {
$undeletableblocktypes = $CFG->undeletableblocktypes;
}
if (!empty($protect) && confirm_sesskey()) {
if (!$block = $DB->get_record('block', array('id'=>$protect))) {
print_error('blockdoesnotexist', 'error');
}
if (!in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes[] = $block->name;
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
block_manager::protect_block((int)$protect);
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($unprotect) && confirm_sesskey()) {
if (!$block = $DB->get_record('block', array('id'=>$unprotect))) {
print_error('blockdoesnotexist', 'error');
}
if (in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes = array_diff($undeletableblocktypes, array($block->name));
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
block_manager::unprotect_block((int)$unprotect);
admin_get_root(true, false); // settings not required - only pages
}
$undeletableblocktypes = block_manager::get_undeletable_block_types();
echo $OUTPUT->header();
echo $OUTPUT->heading($strmanageblocks);

View File

@ -215,12 +215,14 @@ class block_manager {
}
$unaddableblocks = self::get_undeletable_block_types();
$requiredbythemeblocks = self::get_required_by_theme_block_types();
$pageformat = $this->page->pagetype;
foreach($allblocks as $block) {
if (!$bi = block_instance($block->name)) {
continue;
}
if ($block->visible && !in_array($block->name, $unaddableblocks) &&
!in_array($block->name, $requiredbythemeblocks) &&
($bi->instance_allow_multiple() || !$this->is_block_present($block->name)) &&
blocks_name_allowed_in_format($block->name, $pageformat) &&
$bi->user_can_addto($this->page)) {
@ -376,6 +378,80 @@ class block_manager {
}
/**
* @return array names of block types that must exist on every page with this theme.
*/
public static function get_required_by_theme_block_types() {
global $CFG, $PAGE;
$requiredbythemeblocks = false;
if (isset($PAGE->theme->requiredblocks)) {
$requiredbythemeblocks = $PAGE->theme->requiredblocks;
}
if ($requiredbythemeblocks === false) {
return array('navigation', 'settings');
} else if ($requiredbythemeblocks === '') {
return array();
} else if (is_string($requiredbythemeblocks)) {
return explode(',', $requiredbythemeblocks);
} else {
return $requiredbythemeblocks;
}
}
/**
* Make this block type undeletable and unaddable.
*
* @param mixed $blockidorname string or int
*/
public static function protect_block($blockidorname) {
global $DB;
$syscontext = context_system::instance();
require_capability('moodle/site:config', $syscontext);
$block = false;
if (is_int($blockidorname)) {
$block = $DB->get_record('block', array('id' => $blockidorname), 'id, name', MUST_EXIST);
} else {
$block = $DB->get_record('block', array('name' => $blockidorname), 'id, name', MUST_EXIST);
}
$undeletableblocktypes = self::get_undeletable_block_types();
if (!in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes[] = $block->name;
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
}
/**
* Make this block type deletable and addable.
*
* @param mixed $blockidorname string or int
*/
public static function unprotect_block($blockidorname) {
global $DB;
$syscontext = context_system::instance();
require_capability('moodle/site:config', $syscontext);
$block = false;
if (is_int($blockidorname)) {
$block = $DB->get_record('block', array('id' => $blockidorname), 'id, name', MUST_EXIST);
} else {
$block = $DB->get_record('block', array('name' => $blockidorname), 'id, name', MUST_EXIST);
}
$undeletableblocktypes = self::get_undeletable_block_types();
if (in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes = array_diff($undeletableblocktypes, array($block->name));
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
}
/**
* Get the list of "protected" blocks via admin block manager ui.
*
* @return array names of block types that cannot be added or deleted. E.g. array('navigation','settings').
*/
public static function get_undeletable_block_types() {
@ -383,13 +459,9 @@ class block_manager {
$undeletableblocks = false;
if (isset($CFG->undeletableblocktypes)) {
$undeletableblocks = $CFG->undeletableblocktypes;
} else if (isset($PAGE->theme->undeletableblocktypes)) {
$undeletableblocks = $PAGE->theme->undeletableblocktypes;
}
if ($undeletableblocks === false) {
return array('navigation','settings');
} else if ($undeletableblocks === '') {
if (empty($undeletableblocks)) {
return array();
} else if (is_string($undeletableblocks)) {
return explode(',', $undeletableblocks);
@ -596,17 +668,18 @@ class block_manager {
}
// Exclude auto created blocks if they are not undeletable in this theme.
$undeletable = $this->get_undeletable_block_types();
$undeletablecheck = '';
$undeletableparams = array();
$undeletablenotparams = array();
if (!empty($undeletable)) {
list($testsql, $undeletableparams) = $DB->get_in_or_equal($undeletable, SQL_PARAMS_NAMED, 'undeletable');
list($testnotsql, $undeletablenotparams) = $DB->get_in_or_equal($undeletable, SQL_PARAMS_NAMED, 'deletable', false);
$undeletablecheck = 'AND ((bi.blockname ' . $testsql . ' AND bi.requiredbytheme = 1) OR ' .
$requiredbytheme = $this->get_required_by_theme_block_types();
$requiredbythemecheck = '';
$requiredbythemeparams = array();
$requiredbythemenotparams = array();
if (!empty($requiredbytheme)) {
list($testsql, $requiredbythemeparams) = $DB->get_in_or_equal($requiredbytheme, SQL_PARAMS_NAMED, 'requiredbytheme');
list($testnotsql, $requiredbythemenotparams) = $DB->get_in_or_equal($requiredbytheme, SQL_PARAMS_NAMED,
'notrequiredbytheme', false);
$requiredbythemecheck = 'AND ((bi.blockname ' . $testsql . ' AND bi.requiredbytheme = 1) OR ' .
' (bi.blockname ' . $testnotsql . ' AND bi.requiredbytheme = 0))';
} else {
$undeletablecheck = 'AND (bi.requiredbytheme = 0)';
$requiredbythemecheck = 'AND (bi.requiredbytheme = 0)';
}
if (is_null($includeinvisible)) {
@ -680,14 +753,14 @@ class block_manager {
AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)
$visiblecheck
AND b.visible = 1
$undeletablecheck
$requiredbythemecheck
ORDER BY
COALESCE(bp.region, bi.defaultregion),
COALESCE(bp.weight, bi.defaultweight),
bi.id";
$allparams = $params + $parentcontextparams + $pagetypepatternparams + $undeletableparams + $undeletablenotparams;
$allparams = $params + $parentcontextparams + $pagetypepatternparams + $requiredbythemeparams + $requiredbythemenotparams;
$blockinstances = $DB->get_recordset_sql($sql, $allparams);
$this->birecordsbyregion = $this->prepare_per_region_arrays();
@ -992,7 +1065,7 @@ class block_manager {
* chance to initialise themselves via the {@link block_base::specialize()}
* method, before any output is done.
*
* It is also used to create any blocks that are "undeletable" by the current theme.
* It is also used to create any blocks that are "requiredbytheme" by the current theme.
* These blocks that are auto-created have requiredbytheme set on the block instance
* so they are only visible on themes that require them.
*/
@ -1001,9 +1074,9 @@ class block_manager {
$missing = false;
// If there are any un-removable blocks that were not created - force them.
$undeletable = $this->get_undeletable_block_types();
$requiredbytheme = $this->get_required_by_theme_block_types();
if (!$this->fakeblocksonly) {
foreach ($undeletable as $forced) {
foreach ($requiredbytheme as $forced) {
if (empty($forced)) {
continue;
}
@ -1283,7 +1356,8 @@ class block_manager {
protected function user_can_delete_block($block) {
return $this->page->user_can_edit_blocks() && $block->user_can_edit() &&
$block->user_can_addto($this->page) &&
!in_array($block->instance->blockname, self::get_undeletable_block_types());
!in_array($block->instance->blockname, self::get_undeletable_block_types()) &&
!in_array($block->instance->blockname, self::get_required_by_theme_block_types());
}
/**
@ -2453,7 +2527,7 @@ function blocks_add_default_system_blocks() {
$page = new moodle_page();
$page->set_context(context_system::instance());
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => block_manager::get_undeletable_block_types()), '*', null, true);
// We don't add blocks required by the theme, they will be auto-created.
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
if ($defaultmypage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => 1))) {

View File

@ -349,10 +349,10 @@ class theme_config {
public $doctype = 'html5';
/**
* @var string undeletableblocktypes If set to a string, will list the block types that cannot be deleted. Defaults to
* @var string requiredblocks If set to a string, will list the block types that cannot be deleted. Defaults to
* navigation and settings.
*/
public $undeletableblocktypes = false;
public $requiredblocks = false;
//==Following properties are not configurable from theme config.php==
@ -542,7 +542,7 @@ class theme_config {
$configurable = array(
'parents', 'sheets', 'parents_exclude_sheets', 'plugins_exclude_sheets',
'javascripts', 'javascripts_footer', 'parents_exclude_javascripts',
'layouts', 'enable_dock', 'enablecourseajax', 'undeletableblocktypes',
'layouts', 'enable_dock', 'enablecourseajax', 'requiredblocks',
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'uarrow', 'darrow',
'hidefromselector', 'doctype', 'yuicssmodules', 'blockrtlmanipulations',
'lessfile', 'extralesscallback', 'lessvariablescallback', 'blockrendermethod',

View File

@ -545,6 +545,7 @@ class core_blocklib_testcase extends advanced_testcase {
public function test_create_all_block_instances() {
global $CFG, $PAGE, $DB;
$this->setAdminUser();
$this->resetAfterTest();
$regionname = 'side-pre';
$context = context_system::instance();
@ -557,6 +558,7 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we no auto created blocks in boost by default.
$this->assertEmpty($blocks);
// There should be no blocks in the DB.
@ -571,6 +573,7 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we no auto created blocks when viewing a fake blocks only page.
$this->assertEmpty($blocks);
$PAGE->reset_theme_and_output();
@ -581,10 +584,22 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we get the required block for this theme auto-created.
$this->assertCount(2, $blocks);
$undeletable = block_manager::get_undeletable_block_types();
foreach ($undeletable as $blockname) {
$PAGE->reset_theme_and_output();
list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
$context, 'page-type');
$blockmanager->protect_block('html');
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that protecting a block does not make it auto-created.
$this->assertCount(2, $blocks);
$requiredbytheme = block_manager::get_required_by_theme_block_types();
foreach ($requiredbytheme as $blockname) {
$instance = $DB->get_record('block_instances', array('blockname' => $blockname));
$this->assertEquals(1, $instance->requiredbytheme);
}
@ -598,9 +613,10 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we do not return requiredbytheme blocks when they are not required.
$this->assertEmpty($blocks);
// But they should exist in the DB.
foreach ($undeletable as $blockname) {
foreach ($requiredbytheme as $blockname) {
$count = $DB->count_records('block_instances', array('blockname' => $blockname));
$this->assertEquals(1, $count);
}

View File

@ -151,5 +151,5 @@ $THEME->extrascsscallback = 'theme_boost_get_extra_scss';
$THEME->prescsscallback = 'theme_boost_get_pre_scss';
$THEME->yuicssmodules = array();
$THEME->rendererfactory = 'theme_overridden_renderer_factory';
$THEME->undeletableblocktypes = '';
$THEME->requiredblocks = '';
$THEME->addblockposition = BLOCK_ADDBLOCK_POSITION_FLATNAV;

View File

@ -35,7 +35,7 @@ information provided here is intended especially for theme designer.
* A new class .text-ltr may be used to force the direction to LTR. This is especially useful
for forms fields (numbers, emails, URLs must not be RTL'd), and for displaying code
snippets or configuration samples.
* A new theme config 'undeletableblocktypes' allows a theme to define which blocks are deletable.
* A new theme config 'requiredblocks' allows a theme to define which blocks are deletable.
* You may no longer override the following core_course_renderer methods.
See course/upgrade.txt for more information:
- course_modchooser_module_types