]> git.mjollnir.org Git - moodle.git/commitdiff
blocks: MDL-19893 move blocks on page UI - part 2
authortjhunt <tjhunt>
Thu, 30 Jul 2009 10:29:14 +0000 (10:29 +0000)
committertjhunt <tjhunt>
Thu, 30 Jul 2009 10:29:14 +0000 (10:29 +0000)
This updates the DB.

I beleive this is correct, but it is very hairy and badly needs unit tests.

blocks/edit_form.php
lang/en_utf8/error.php
lib/blocklib.php

index 14bfa5fb8f667cc3e0852307b4a60a7ca8c7bff0..74d3d3b8820dc0492ad9be824ac211b5c1335311 100644 (file)
@@ -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);
index b2d842d6006e10257129e127ff168d5a483c4499..b46f2d5c607907e3ff653e8978fcb1ab74440002 100644 (file)
@@ -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';
index 0aa7f80c32cc5efd5e2ad63676a5b6da275949ff..a1e69c69b3da9ecb3b34c107ea574280155b2f32 100644 (file)
@@ -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');