mirror of
https://github.com/moodle/moodle.git
synced 2025-04-25 10:26:17 +02:00
blocks: MDL-19893 move blocks on page UI - part 1
This does all the UI. It does not yet update the DB when you click to complete the action.
This commit is contained in:
parent
52fa87553e
commit
00a24d44f7
@ -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) {
|
||||
|
@ -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';
|
||||
|
288
lib/blocklib.php
288
lib/blocklib.php
@ -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 =======================
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user