]> git.mjollnir.org Git - moodle.git/commitdiff
blocks: MDL-19893 move blocks on page UI - part 1
authortjhunt <tjhunt>
Thu, 30 Jul 2009 08:22:12 +0000 (08:22 +0000)
committertjhunt <tjhunt>
Thu, 30 Jul 2009 08:22:12 +0000 (08:22 +0000)
This does all the UI. It does not yet update the DB when you click to complete the action.

blocks/moodleblock.class.php
lang/en_utf8/block.php
lib/blocklib.php
lib/outputlib.php
theme/standard/styles_color.css
theme/standard/styles_layout.css

index b161989a7a42c4ba39680a0580256163c5f80fa5..5d87a7cc7c93fa99970777895cd1cc217d2743dc 100644 (file)
@@ -381,7 +381,7 @@ class block_base {
         }
 
         if ($this->page->user_is_editing()) {
-            $bc->controls = block_edit_controls($this, $this->page);
+            $bc->controls = $this->page->blocks->edit_controls($this);
         }
 
         if ($this->is_empty() && !$bc->controls) {
index ce33f3a6197c2772d122780ac5c0465d5cc814a8..70b576f73e01baeabb0fc337707bd546557a856d 100644 (file)
@@ -8,6 +8,8 @@ $string['bracketfirst'] = '$a (first)';
 $string['bracketlast'] = '$a (last)';
 $string['defaultregion'] = 'Default region';
 $string['defaultweight'] = 'Default weight';
+$string['moveblockhere'] = 'Move block here';
+$string['movingthisblockcancel'] = 'Moving this block ($a)';
 $string['onthispage'] = 'On this page';
 $string['pagetypes'] = 'Page types';
 $string['region'] = 'Region';
index d16ab6cfd97e06a140c15a7d97badf073f22aeb2..6787a37edf650335ed222816451d43b1b4b58380 100644 (file)
@@ -131,6 +131,17 @@ class block_manager {
      */
     protected $extracontent = array();
 
+    /**
+     * Used by the block move id, to track whether a block is cuurently being moved.
+     *
+     * Whe you click on the move icon of a block, first the page needs to reload with
+     * extra UI for chooseing a new position for a particular block. In that situation
+     * this field holds the id of the block being moved.
+     *
+     * @var integer|null
+     */
+    protected $movingblock = null;
+
 /// Constructor ================================================================
 
     /**
@@ -260,6 +271,18 @@ class block_manager {
         return $this->visibleblockcontent[$region];
     }
 
+    /**
+     * Helper method used by get_content_for_region.
+     * @param string $region region name
+     * @param float $weight weight. May be fractional, since you may want to move a block
+     * between ones with weight 2 and 3, say ($weight would be 2.5).
+     * @return string URL for moving block $this->movingblock to this position.
+     */
+    protected function get_move_target_url($region, $weight) {
+        return $this->page->url->out(false, array('bui_moveid' => $this->movingblock,
+                'bui_newregion' => $region, 'bui_newweight' => $weight, 'sesskey' => sesskey()), false);
+    }
+
     /**
      * Determine whether a region contains anything. (Either any real blocks, or
      * the add new block UI.)
@@ -392,7 +415,6 @@ class block_manager {
             }
         }
 
-        // The code here needs to be consistent with the code in block_load_for_page.
         if (is_null($includeinvisible)) {
             $includeinvisible = $this->page->user_is_editing();
         }
@@ -683,19 +705,59 @@ class block_manager {
     }
 
     /**
-     * Return an array of content vars from a set of block instances
+     * Return an array of content objects from a set of block instances
      *
      * @param array $instances An array of block instances
-     * @return array An array of content vars
+     * @param moodle_renderer_base The renderer to use.
+     * @param string $region the region name.
+     * @return array An array of block_content (and possibly block_move_target) objects.
      */
-    protected function create_block_contents($instances, $output) {
+    protected function create_block_contents($instances, $output, $region) {
         $results = array();
+
+        $lastweight = 0;
+        $lastblock = 0;
+        if ($this->movingblock) {
+            $first = reset($instances);
+            if ($first) {
+                $lastweight = $first->instance->weight - 2;
+            }
+
+            $strmoveblockhere = get_string('moveblockhere', 'block');
+        }
+
         foreach ($instances as $instance) {
             $content = $instance->get_content_for_output($output);
-            if (!empty($content)) {
-                $results[] = $content;
+            if (empty($content)) {
+                continue;
+            }
+
+            if ($this->movingblock && $lastweight != $instance->instance->weight &&
+                    $content->blockinstanceid != $this->movingblock && $lastblock != $this->movingblock) {
+                $bmt = new block_move_target();
+                $bmt->text = $strmoveblockhere;
+                $bmt->url = $this->get_move_target_url($region, ($lastweight + $instance->instance->weight)/2);
+                $results[] = $bmt;
+            }
+
+            if ($content->blockinstanceid == $this->movingblock) {
+                $content->add_class('beingmoved');
+                $content->annotation .= get_string('movingthisblockcancel', 'block',
+                        $output->link($this->page->url, get_string('cancel')));
             }
+
+            $results[] = $content;
+            $lastweight = $instance->instance->weight;
+            $lastblock = $instance->instance->id;
+        }
+
+        if ($this->movingblock && $lastblock != $this->movingblock) {
+            $bmt = new block_move_target();
+            $bmt->text = $strmoveblockhere;
+            $bmt->url = $this->get_move_target_url($region, $lastweight + 1);
+            $results[] = $bmt;
         }
+
         return $results;
     }
 
@@ -724,7 +786,7 @@ class block_manager {
             if (array_key_exists($region, $this->extracontent)) {
                 $contents = $this->extracontent[$region];
             }
-            $contents = array_merge($contents, $this->create_block_contents($this->blockinstances[$region], $output));
+            $contents = array_merge($contents, $this->create_block_contents($this->blockinstances[$region], $output, $region));
             if ($region == $this->defaultregion) {
                 $addblockui = block_add_block_ui($this->page, $output);
                 if ($addblockui) {
@@ -737,6 +799,58 @@ class block_manager {
 
 /// Process actions from the URL ===============================================
 
+    /**
+     * Get the appropriate list of editing icons for a block. This is used
+     * to set {@link block_contents::$controls} in {@link block_base::get_contents_for_output()}.
+     *
+     * @param $output The core_renderer to use when generating the output. (Need to get icon paths.)
+     * @return an array in the format for {@link block_contents::$controls}
+     */
+    public function edit_controls($block) {
+        global $CFG;
+
+        $controls = array();
+        $actionurl = $this->page->url->out(false, array('sesskey'=> sesskey()), false);
+
+        // Assign roles icon.
+        if (has_capability('moodle/role:assign', $block->context)) {
+            $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
+                    '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($this->page->url->out_returnurl()),
+                    'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'));
+        }
+
+        if ($this->page->user_can_edit_blocks()) {
+            // Show/hide icon.
+            if ($block->instance->visible) {
+                $controls[] = array('url' => $actionurl . '&bui_hideid=' . $block->instance->id,
+                        'icon' => 't/hide', 'caption' => get_string('hide'));
+            } else {
+                $controls[] = array('url' => $actionurl . '&bui_showid=' . $block->instance->id,
+                        'icon' => 't/show', 'caption' => get_string('show'));
+            }
+        }
+
+        if ($this->page->user_can_edit_blocks() || $block->user_can_edit()) {
+            // Edit config icon - always show - needed for positioning UI.
+            $controls[] = array('url' => $actionurl . '&bui_editid=' . $block->instance->id,
+                    'icon' => 't/edit', 'caption' => get_string('configuration'));
+        }
+
+        if ($this->page->user_can_edit_blocks() && $block->user_can_edit() && $block->user_can_addto($this->page)) {
+            // Delete icon.
+            $controls[] = array('url' => $actionurl . '&bui_deleteid=' . $block->instance->id,
+                    'icon' => 't/delete', 'caption' => get_string('delete'));
+        }
+
+        if ($this->page->user_can_edit_blocks()) {
+            // Move icon.
+            $controls[] = array('url' => $actionurl . '&bui_moveid=' . $block->instance->id,
+                    'icon' => 't/move', 'caption' => get_string('move'));
+        }
+
+        return $controls;
+    }
+
     /**
      * Process any block actions that were specified in the URL.
      *
@@ -746,8 +860,12 @@ class block_manager {
      * @return boolean true if anything was done. False if not.
      */
     public function process_url_actions() {
+        if (!$this->page->user_is_editing()) {
+            return false;
+        }
         return $this->process_url_add() || $this->process_url_delete() ||
-            $this->process_url_show_hide() || $this->process_url_edit();
+            $this->process_url_show_hide() || $this->process_url_edit() ||
+            $this->process_url_move();
     }
 
     /**
@@ -762,7 +880,7 @@ class block_manager {
 
         confirm_sesskey();
 
-        if (!$this->page->user_is_editing() && !$this->page->user_can_edit_blocks()) {
+        if ($this->page->user_can_edit_blocks()) {
             throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('addblock'));
         }
 
@@ -956,6 +1074,45 @@ class block_manager {
             exit;
         }
     }
+
+    /**
+     * Handle showing/processing the submission from the block editing form.
+     * @return boolean true if the form was submitted and the new config saved. Does not
+     *      return if the editing form was displayed. False otherwise.
+     */
+    public function process_url_move() {
+        global $CFG, $DB, $PAGE;
+
+        $blockid = optional_param('bui_moveid', null, PARAM_INTEGER);
+        if (!$blockid) {
+            return false;
+        }
+
+        confirm_sesskey();
+
+        $block = $this->find_instance($blockid);
+
+        if (!$this->page->user_can_edit_blocks()) {
+            throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock'));
+        }
+
+        $newregion = optional_param('bui_newregion', '', PARAM_ALPHANUMEXT);
+        $newweight = optional_param('bui_newweight', null, PARAM_FLOAT);
+        if (!$newregion || is_null($newweight)) {
+            // Don't have a valid target position yet, must be just starting the move.
+            $this->movingblock = $blockid;
+            $this->page->ensure_param_not_in_url('bui_moveid');
+            return false;
+        }
+
+        // Work out if we should be setting defaultposition or just position on this page.
+        // TODO$block = $this->
+
+        $this->page->ensure_param_not_in_url('bui_moveid');
+        $this->page->ensure_param_not_in_url('bui_newregion');
+        $this->page->ensure_param_not_in_url('bui_newweight');
+        return true;
+    }
 }
 
 /// Helper functions for working with block classes ============================
@@ -975,66 +1132,6 @@ function block_method_result($blockname, $method, $param = NULL) {
     return call_user_func(array('block_'.$blockname, $method), $param);
 }
 
-/**
- * Load a block instance, with position information about where that block appears
- * on a given page.
- *
- * @param integer$blockid the block_instance.id.
- * @param moodle_page $page the page the block is appearing on.
- * @return block_base the requested block.
- */
-function block_load_for_page($blockid, $page) {
-    global $DB;
-
-    // The code here needs to be consistent with the code in block_manager::load_blocks.
-    $params = array(
-        'blockinstanceid' => $blockid,
-        'subpage' => $page->subpage,
-        'contextid' => $page->context->id,
-        'pagetype' => $page->pagetype,
-        'contextblock' => CONTEXT_BLOCK,
-    );
-    $sql = "SELECT
-                bi.id,
-                bp.id AS blockpositionid,
-                bi.blockname,
-                bi.parentcontextid,
-                bi.showinsubcontexts,
-                bi.pagetypepattern,
-                bi.subpagepattern,
-                bi.defaultregion,
-                bi.defaultweight,
-                COALESCE(bp.visible, 1) AS visible,
-                COALESCE(bp.region, bi.defaultregion) AS region,
-                COALESCE(bp.weight, bi.defaultweight) AS weight,
-                bi.configdata,
-                ctx.id AS ctxid,
-                ctx.path AS ctxpath,
-                ctx.depth AS ctxdepth,
-                ctx.contextlevel AS ctxlevel
-
-            FROM {block_instances} bi
-            JOIN {block} b ON bi.blockname = b.name
-            LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id
-                                              AND bp.contextid = :contextid
-                                              AND bp.pagetype = :pagetype
-                                              AND bp.subpage = :subpage
-            JOIN {context} ctx ON ctx.contextlevel = :contextblock
-                                  AND ctx.instanceid = bi.id
-
-            WHERE
-            bi.id = :blockinstanceid
-            AND b.visible = 1
-
-            ORDER BY
-                COALESCE(bp.region, bi.defaultregion),
-                COALESCE(bp.weight, bi.defaultweight),
-                bi.id";
-    $bi = $DB->get_record_sql($sql, $params, MUST_EXIST);
-    $bi = make_context_subobj($bi);
-    return block_instance($bi->blockname, $bi, $page);
-}
-
 /**
  * Creates a new object of the specified block class.
  *
@@ -1149,59 +1246,6 @@ function block_add_block_ui($page, $output) {
     return $bc;
 }
 
-/**
- * Get the appropriate list of editing icons for a block. This is used
- * to set {@link block_contents::$controls} in {@link block_base::get_contents_for_output()}.
- *
- * @param $output The core_renderer to use when generating the output. (Need to get icon paths.)
- * @return an array in the format for {@link block_contents::$controls}
- * @since Moodle 2.0.
- */
-function block_edit_controls($block, $page) {
-    global $CFG;
-
-    $controls = array();
-    $actionurl = $page->url->out(false, array('sesskey'=> sesskey()), false);
-
-    // Assign roles icon.
-    if (has_capability('moodle/role:assign', $block->context)) {
-        $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
-                '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($page->url->out_returnurl()),
-                'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'));
-    }
-
-    if ($page->user_can_edit_blocks()) {
-        // Show/hide icon.
-        if ($block->instance->visible) {
-            $controls[] = array('url' => $actionurl . '&bui_hideid=' . $block->instance->id,
-                    'icon' => 't/hide', 'caption' => get_string('hide'));
-        } else {
-            $controls[] = array('url' => $actionurl . '&bui_showid=' . $block->instance->id,
-                    'icon' => 't/show', 'caption' => get_string('show'));
-        }
-    }
-
-    if ($page->user_can_edit_blocks() || $block->user_can_edit()) {
-        // Edit config icon - always show - needed for positioning UI.
-        $controls[] = array('url' => $actionurl . '&bui_editid=' . $block->instance->id,
-                'icon' => 't/edit', 'caption' => get_string('configuration'));
-    }
-
-    if ($page->user_can_edit_blocks() && $block->user_can_edit() && $block->user_can_addto($page)) {
-        // Delete icon.
-        $controls[] = array('url' => $actionurl . '&bui_deleteid=' . $block->instance->id,
-                'icon' => 't/delete', 'caption' => get_string('delete'));
-    }
-
-    if ($page->user_can_edit_blocks()) {
-        // Move icon.
-        $controls[] = array('url' => $page->url->out(false, array('moveblockid' => $block->instance->id)),
-                'icon' => 't/move', 'caption' => get_string('move'));
-    }
-
-    return $controls;
-}
-
 // Functions that have been deprecated by block_manager =======================
 
 /**
index a9a441a803795adff8ac59aef2e385d026ef887f..839a0d3142e22d6532227a52f0438fe5512d1854 100644 (file)
@@ -2322,6 +2322,7 @@ class moodle_core_renderer extends moodle_renderer_base {
 
         $output .= $this->output_end_tag('div');
         $output .= $this->output_end_tag('div');
+
         if ($bc->annotation) {
             $output .= $this->output_tag('div', array('class' => 'blockannotation'), $bc->annotation);
         }
@@ -2378,13 +2379,30 @@ class moodle_core_renderer extends moodle_renderer_base {
      */
     public function blocks_for_region($region) {
         $blockcontents = $this->page->blocks->get_content_for_region($region, $this);
+        
         $output = '';
         foreach ($blockcontents as $bc) {
-            $output .= $this->block($bc, $region);
+            if ($bc instanceof block_contents) {
+                $output .= $this->block($bc, $region);
+            } else if ($bc instanceof block_move_target) {
+                $output .= $this->block_move_target($bc);
+            } else {
+                throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
+            }
         }
         return $output;
     }
 
+    /**
+     * Output a place where the block that is currently being moved can be dropped.
+     * @param block_move_target $target with the necessary details.
+     * @return string the HTML to be output.
+     */
+    public function block_move_target($target) {
+        return $this->output_tag('a', array('href' => $target->url, 'class' => 'blockmovetarget'),
+                $this->output_tag('span', array('class' => 'accesshide'), $target->text));
+    }
+
     /**
      * Given a html_textarea object, outputs an <a> tag that uses the object's attributes.
      *
@@ -2404,7 +2422,7 @@ class moodle_core_renderer extends moodle_renderer_base {
      * @return string HTML fragment
      */
     public function link($link, $text=null) {
-        $attributes = array('href' => $link);
+        $attributes = array();
 
         if (is_a($link, 'html_link')) {
             $link->prepare();
@@ -2418,6 +2436,9 @@ class moodle_core_renderer extends moodle_renderer_base {
 
         } else if (empty($text)) {
             throw new coding_exception('$OUTPUT->link() must have a string as second parameter if the first param ($link) is a string');
+
+        } else {
+            $attributes['href'] = prepare_url($link);
         }
 
         return $this->output_tag('a', $attributes, $text);
@@ -3992,6 +4013,31 @@ class block_contents extends moodle_html_component {
 }
 
 
+/**
+ * This class represents a target for where a block can go when it is being moved.
+ *
+ * This needs to be rendered as a form with the given hidden from fields, and
+ * clicking anywhere in the form should submit it. The form action should be
+ * $PAGE->url.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class block_move_target extends moodle_html_component {
+    /**
+     * List of hidden form fields.
+     * @var array
+     */
+    public $url = array();
+    /**
+     * List of hidden form fields.
+     * @var array
+     */
+    public $text = '';
+}
+
+
 /**
  * Holds all the information required to render a <table> by
  * {@see moodle_core_renderer::table()} or by an overridden version of that
index 6acbb00c7466618b6f10737458220617b3c92cfb..1d93c2d7f4f248493c5cc8051df02582bee8cb39 100644 (file)
@@ -491,7 +491,21 @@ table.flexible .r1 {
 .block-region .hidden .header {
   border-bottom-color: #dddddd;
 }
+.blockannotation {
+  color:#aaa;
+}
 
+.blockmovetarget {
+  background-color: #fcc;
+  border-color: #f88;
+}
+.blockmovetarget:hover {
+  background-color: #f88;
+  border-color: #c00;
+}
+.sideblock.beingmoved {
+  border-color: #f88;
+}
 
 /***
  *** Blogs
index 711b2c57a435a5bb8f2915547bf0c0f3a53e6b86..f522f24bd0cb7f569df2ede84f6bdb974c70c60f 100644 (file)
@@ -1610,6 +1610,22 @@ a.skip:focus, a.skip:active {
 .sideblock .header .icon.edit {
   margin-right: 6px;
 }
+.blockannotation {
+  font-size:0.75em;
+  margin: -1em 0 1em;
+}
+
+.blockmovetarget {
+  display: block;
+  height: 1em;
+  margin-bottom: 1em;
+  border-width: 2px;
+  border-style: dashed;
+}
+.sideblock.beingmoved {
+  border-width: 2px;
+  border-style: dashed;
+}
 
 .sideblock .content {
   padding: 4px;