*/
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 ================================================================
/**
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.)
}
}
- // 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();
}
}
/**
- * 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;
}
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) {
/// 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.
*
* @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();
}
/**
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'));
}
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 ============================
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.
*
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 =======================
/**
$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);
}
*/
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.
*
* @return string HTML fragment
*/
public function link($link, $text=null) {
- $attributes = array('href' => $link);
+ $attributes = array();
if (is_a($link, 'html_link')) {
$link->prepare();
} 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);
}
+/**
+ * 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