From 2cdb8d84528460d488d9de171d68ab976558bd42 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Thu, 30 Jul 2009 10:29:14 +0000 Subject: [PATCH] blocks: MDL-19893 move blocks on page UI - part 2 This updates the DB. I beleive this is correct, but it is very hairy and badly needs unit tests. --- blocks/edit_form.php | 7 +-- lang/en_utf8/error.php | 1 + lib/blocklib.php | 125 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/blocks/edit_form.php b/blocks/edit_form.php index 14bfa5fb8f..74d3d3b882 100644 --- a/blocks/edit_form.php +++ b/blocks/edit_form.php @@ -35,7 +35,6 @@ require_once($CFG->libdir . '/formslib.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class block_edit_form extends moodleform { - const MAX_WEIGHT = 10; /** * The block instance we are editing. * @var block_base @@ -66,13 +65,13 @@ class block_edit_form extends moodleform { // If the current weight of the block is out-of-range, add that option in. $blockweight = $this->block->instance->weight; $weightoptions = array(); - if ($blockweight < -self::MAX_WEIGHT) { + if ($blockweight < -block_manager::MAX_WEIGHT) { $weightoptions[$blockweight] = $blockweight; } - for ($i = -self::MAX_WEIGHT; $i <= self::MAX_WEIGHT; $i++) { + for ($i = -block_manager::MAX_WEIGHT; $i <= block_manager::MAX_WEIGHT; $i++) { $weightoptions[$i] = $i; } - if ($blockweight > self::MAX_WEIGHT) { + if ($blockweight > block_manager::MAX_WEIGHT) { $weightoptions[$blockweight] = $blockweight; } $first = reset($weightoptions); diff --git a/lang/en_utf8/error.php b/lang/en_utf8/error.php index b2d842d600..b46f2d5c60 100644 --- a/lang/en_utf8/error.php +++ b/lang/en_utf8/error.php @@ -424,6 +424,7 @@ $string['unknowaction']= 'Unknown action!'; $string['unknowcategory'] = 'Category not known!'; $string['unknowcontext'] = 'This is an unknown context ($a) in get_child_contexts!'; $string['unknowformat'] = 'Format not known ($a)'; +$string['unknownblockregion'] = 'The block region \'$a\' is not recognised on this page.'; $string['unknowncourse'] = 'Unknown course named \"$a\"'; $string['unknowncourseidnumber'] = 'Unknown Course ID \"$a\"'; $string['unknowncourserequest'] = 'Unknown course request'; diff --git a/lib/blocklib.php b/lib/blocklib.php index 0aa7f80c32..a1e69c69b3 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -82,6 +82,11 @@ class block_not_on_page_exception extends moodle_exception { * @since Moodle 2.0 */ class block_manager { + /** + * The UI normally only shows block weights between -MAX_WEIGHT and MAX_WEIGHT, + * although other weights are valid. + */ + const MAX_WEIGHT = 10; /// Field declarations ========================================================= @@ -591,6 +596,67 @@ class block_manager { } } + /** + * Move a block to a new position on this page. + * + * If this block cannot appear on any other pages, then we change defaultposition/weight + * in the block_instances table. Otherwise we just set the postition on this page. + * + * @param $blockinstanceid the block instance id. + * @param $newregion the new region name. + * @param $newweight the new weight. + */ + public function reposition_block($blockinstanceid, $newregion, $newweight) { + global $DB; + + $this->check_region_is_known($newregion); + $inst = $this->find_instance($blockinstanceid); + + $bi = $inst->instance; + if ($bi->weight == $bi->defaultweight && $bi->region == $bi->defaultregion && + !$bi->showinsubcontexts && strpos($bi->pagetypepattern, '*') === false && + (!$this->page->subpage || $bi->subpagepattern)) { + + // Set default position + $newbi = new stdClass; + $newbi->id = $bi->id; + $newbi->defaultregion = $newregion; + $newbi->defaultweight = $newweight; + $DB->update_record('block_instances', $newbi); + + if ($bi->blockpositionid) { + $bp = new stdClass; + $bp->id = $bi->blockpositionid; + $bp->region = $newregion; + $bp->weight = $newweight; + $DB->update_record('block_positions', $bp); + } + + } else { + // Just set position on this page. + $bp = new stdClass; + $bp->region = $newregion; + $bp->weight = $newweight; + + if ($bi->blockpositionid) { + $bp->id = $bi->blockpositionid; + $DB->update_record('block_positions', $bp); + + } else { + $bp->blockinstanceid = $bi->id; + $bp->contextid = $this->page->context->id; + $bp->pagetype = $this->page->pagetype; + if ($this->page->subpage) { + $bp->subpage = $this->page->subpage; + } else { + $bp->subpage = ''; + } + $bp->visible = $bi->visible; + $DB->insert_record('block_positions', $bp); + } + } + } + /** * Find a given block by its instance id * @@ -1105,8 +1171,63 @@ class block_manager { return false; } - // Work out if we should be setting defaultposition or just position on this page. - // TODO$block = $this-> + if (!$this->is_known_region($newregion)) { + throw new moodle_exception('unknownblockregion', '', $this->page->url, $newregion); + } + + // Move this block. This may involve moving other nearby blocks. + $blocks = $this->birecordsbyregion[$newregion]; + + // First we find the nearest gap in the list of weights. + $spareweights = array(); + $usedweights = array(); + for ($i = -self::MAX_WEIGHT; $i <= self::MAX_WEIGHT; $i++) { + $spareweights[$i] = $i; + $usedweights[$i] = array(); + } + foreach ($blocks as $bi) { + if ($bi->id == $block->instance->id) { + continue; + } + unset($spareweights[$bi->weight]); + $usedweights[$bi->weight][] = $bi->id; + } + + $bestdistance = max(abs($newweight - self::MAX_WEIGHT), abs($newweight + self::MAX_WEIGHT)) + 1; + $bestgap = null; + foreach ($spareweights as $spareweight) { + if (abs($newweight - $spareweight) < $bestdistance) { + $bestdistance = abs($newweight - $spareweight); + $bestgap = $spareweight; + } + } + + // If there is no gap, we have to go outside -self::MAX_WEIGHT .. self::MAX_WEIGHT. + if (is_null($bestgap)) { + $bestgap = self::MAX_WEIGHT + 1; + while (!empty($usedweights[$bestgap])) { + $bestgap++; + } + } + + // Now we know the gap we are aiming for, so move all the blocks along. + if ($bestgap < $newweight) { + $newweight = floor($newweight); + for ($weight = $bestgap + 1; $weight <= $newweight; $weight++) { + foreach ($usedweights[$weight] as $biid) { + $this->reposition_block($biid, $newregion, $weight - 1); + } + } + $this->reposition_block($block->instance->id, $newregion, $newweight); + } else { + $newweight = ceil($newweight); + for ($weight = $bestgap - 1; $weight >= $newweight; $weight--) { + foreach ($usedweights[$weight] as $biid) { + $this->reposition_block($biid, $newregion, $weight + 1); + } + } + $this->reposition_block($block->instance->id, $newregion, $newweight); + } $this->page->ensure_param_not_in_url('bui_moveid'); $this->page->ensure_param_not_in_url('bui_newregion'); -- 2.39.5