This mostly works now, but ...
* The UI needs further work. In particular we need a non-advanced mode.
* This only works for blocks that use a new edit_form.php to replace config_instance.html.
* .. and so far I have only implemented edit_form.php for the HTML block so far.
* Needs to be enabled (with no block-specific config) for blocks without instance config, so you can control their positioning.
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This script is used to edit the settings for a block instance.
+ *
+ * It works with the {@link block_edit_form} class, or rather the particular
+ * subclass defined by this block, to do the editing.
+ *
+ * @package moodlecore
+ * @copyright 2009 Tim Hunt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(dirname(__FILE__) . '/../config.php');
+require_once($CFG->dirroot . '/blocks/edit_form.php');
+
+$blockid = required_param('id', PARAM_INTEGER);
+$pagecontextid = required_param('pagecontextid', PARAM_INTEGER);
+$pagetype = required_param('pagetype', PARAM_ALPHANUMEXT);
+$subpage = optional_param('subpage', null, PARAM_ALPHANUMEXT);
+$returnurl = required_param('returnurl', PARAM_LOCALURL);
+
+$urlparams = array(
+ 'id' => $blockid,
+ 'pagecontextid' => $pagecontextid,
+ 'pagetype' => $pagetype,
+ 'returnurl' => $returnurl,
+);
+if ($subpage) {
+ $urlparams['subpage'] = $subpage;
+}
+$PAGE->set_url('blocks/edit.php', $urlparams);
+
+require_login();
+
+$blockpage = new moodle_page();
+$blockpage->set_context(get_context_instance_by_id($pagecontextid));
+$blockpage->set_pagetype($pagetype);
+$blockpage->set_subpage($subpage);
+$url = new moodle_url($returnurl);
+$blockpage->set_url($url->out(true), $url->params());
+
+$block = block_load_for_page($blockid, $blockpage);
+
+if (!$block->user_can_edit() || (!$block->instance_allow_multiple() && !$block->instance_allow_config())) {
+ throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('editblock'));
+}
+
+$PAGE->set_context($block->context);
+$PAGE->set_generaltype('form');
+
+$formfile = $CFG->dirroot . '/blocks/' . $block->name() . '/edit_form.php';
+if (is_readable($formfile)) {
+ require_once($formfile);
+ $classname = 'block_' . $block->name() . '_edit_form';
+} else {
+ $classname = 'block_edit_form';
+}
+$mform = new $classname($block, $blockpage);
+
+$mform->set_data($block->instance);
+
+if ($mform->is_cancelled()) {
+ redirect($CFG->wwwroot . '/' . $returnurl);
+
+} else if ($data = $mform->get_data()) {
+ $bi = new stdClass;
+ $bi->id = $block->instance->id;
+ $bi->showinsubcontexts = $data->showinsubcontexts;
+ $bi->pagetypepattern = $data->pagetypepattern;
+ if (empty($data->subpagepattern) || $data->subpagepattern == '%@NULL@%') {
+ $bi->subpagepattern = null;
+ } else {
+ $bi->subpagepattern = $data->subpagepattern;
+ }
+ $bi->defaultregion = $data->defaultregion;
+ $bi->defaultweight = $data->defaultweight;
+ $DB->update_record('block_instances', $bi);
+
+ $config = new stdClass;
+ foreach ($data as $configfield => $value) {
+ if (strpos($configfield, 'config_') !== 0) {
+ continue;
+ }
+ $field = substr($configfield, 7);
+ $config->$field = $value;
+ }
+ $block->instance_config_save($config);
+
+ $bp = new stdClass;
+ $bp->visible = $data->visible;
+ $bp->region = $data->region;
+ $bp->weight = $data->weight;
+ $needbprecord = !$data->visible || $data->region != $data->defaultregion ||
+ $data->weight != $data->defaultweight;
+
+ if ($block->instance->blockpositionid && !$needbprecord) {
+ $DB->delete_records('block_positions', array('id' => $block->instance->blockpositionid));
+
+ } else if ($block->instance->blockpositionid && $needbprecord) {
+ $bp->id = $block->instance->blockpositionid;
+ $DB->update_record('block_positions', $bp);
+
+ } else if ($needbprecord) {
+ $bp->blockinstanceid = $block->instance->id;
+ $bp->contextid = $blockpage->contextid;
+ $bp->pagetype = $blockpage->pagetype;
+ if ($blockpage->subpage) {
+ $bp->subpage = $blockpage->subpage;
+ } else {
+ $bp->subpage = null;
+ }
+ $DB->insert_record('block_positions', $bp);
+ }
+
+ redirect($CFG->wwwroot . '/' . $returnurl);
+
+} else {
+ $strheading = get_string('editinga', $block->name());
+ if (strpos($strheading, '[[') === 0) {
+ $strheading = get_string('blockconfiga', 'moodle', $block->get_title());
+ }
+
+$PAGE->set_title($strheading);
+ $PAGE->set_heading($strheading);
+
+ echo $OUTPUT->header();
+ echo $OUTPUT->heading($strheading, 2);
+
+ $mform->display();
+
+ echo $OUTPUT->footer();
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines the base class form used by blocks/edit.php to edit block instance configuration.
+ *
+ * It works with the {@link block_edit_form} class, or rather the particular
+ * subclass defined by this block, to do the editing.
+ *
+ * @package moodlecore
+ * @copyright 2009 Tim Hunt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir . '/formslib.php');
+
+/**
+ * The base class form used by blocks/edit.php to edit block instance configuration.
+ *
+ * @copyright 2009 Tim Hunt
+ * @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
+ */
+ public $block;
+ /**
+ * The page we are editing this block in association with.
+ * @var moodle_page
+ */
+ public $page;
+
+ function __construct($block, $page) {
+ global $CFG;
+ $this->block = $block;
+ $this->page = $page;
+ parent::moodleform(block_edit_url($block, $page));
+ }
+
+ function definition() {
+ $mform =& $this->_form;
+
+ // First show fields specific to this type of block.
+ $this->specific_definition($mform);
+
+ // Then show the fields about where this block appears.
+ $mform->addElement('header', 'whereheader', get_string('wherethisblockappears', 'block'));
+
+ // 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) {
+ $weightoptions[$blockweight] = $blockweight;
+ }
+ for ($i = -self::MAX_WEIGHT; $i <= self::MAX_WEIGHT; $i++) {
+ $weightoptions[$i] = $i;
+ }
+ if ($blockweight > self::MAX_WEIGHT) {
+ $weightoptions[$blockweight] = $blockweight;
+ }
+ $first = reset($weightoptions);
+ $weightoptions[$first] = get_string('bracketfirst', 'block', $first);
+ $last = end($weightoptions);
+ $weightoptions[$last] = get_string('bracketlast', 'block', $last);
+
+ $regionoptions = $this->page->theme->get_all_block_regions();
+
+ $parentcontext = get_context_instance_by_id($this->block->instance->parentcontextid);
+ $mform->addElement('static', 'contextname', get_string('thisblockbelongsto', 'block'), print_context_name($parentcontext));
+
+ $mform->addElement('selectyesno', 'showinsubcontexts', get_string('appearsinsubcontexts', 'block'));
+
+ $pagetypeoptions = matching_page_type_patterns($this->page->pagetype);
+ $pagetypeoptions = array_combine($pagetypeoptions, $pagetypeoptions);
+ $mform->addElement('select', 'pagetypepattern', get_string('pagetypes', 'block'), $pagetypeoptions);
+
+ if ($this->page->subpage) {
+ $subpageoptions = array(
+ '%@NULL@%' => get_string('anypagematchingtheabove', 'block'),
+ $this->page->subpage => get_string('thisspecificpage', 'block', $this->page->subpage),
+ );
+ $mform->addElement('select', 'subpagepattern', get_string('subpages', 'block'), $subpageoptions);
+ }
+
+ $defaultregionoptions = $regionoptions;
+ $defaultregion = $this->block->instance->defaultregion;
+ if (!array_key_exists($defaultregion, $defaultregionoptions)) {
+ $defaultregionoptions[$defaultregion] = $defaultregion;
+ }
+ $mform->addElement('select', 'defaultregion', get_string('defaultregion', 'block'), $defaultregionoptions);
+
+ $mform->addElement('select', 'defaultweight', get_string('defaultweight', 'block'), $weightoptions);
+
+ // Where this block is positioned on this page.
+ $mform->addElement('header', 'whereheader', get_string('onthispage', 'block'));
+
+ $mform->addElement('selectyesno', 'visible', get_string('visible', 'block'));
+
+ $blockregion = $this->block->instance->region;
+ if (!array_key_exists($blockregion, $regionoptions)) {
+ $regionoptions[$blockregion] = $blockregion;
+ }
+ $mform->addElement('select', 'region', get_string('region', 'block'), $regionoptions);
+
+ $mform->addElement('select', 'weight', get_string('weight', 'block'), $weightoptions);
+
+ $this->add_action_buttons();
+ }
+
+ function set_data($defaults) {
+ // Copy block config into config_ fields.
+ if (!empty($this->block->config)) {
+ foreach ($this->block->config as $field => $value) {
+ $configfield = 'config_' . $field;
+ $defaults->$configfield = $value;
+ }
+ }
+
+ // Munge ->subpagepattern becuase HTML selects don't play nicely with NULLs.
+ if (empty($defaults->subpagepattern)) {
+ $defaults->subpagepattern = '%@NULL@%';
+ }
+
+ parent::set_data($defaults);
+ }
+
+ /**
+ * Override this to create any form fields specific to this type of block.
+ * @param object $mform the form being built.
+ */
+ protected function specific_definition($mform) {
+ // By default, do nothing.
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @package moodlecore
+ * @copyright 2009 Tim Hunt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_html_edit_form extends block_edit_form {
+ protected function specific_definition($mform) {
+ // Then show the fields about where this block appears.
+ $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+ $mform->addElement('text', 'config_title', get_string('configtitle', 'block_html'));
+ $mform->setType('configtitle', PARAM_MULTILANG);
+
+ // TODO MDL-19844 should use the new editor field type.
+ $mform->addElement('htmleditor', 'config_text', get_string('configcontent', 'block_html'));
+ $mform->setType('config_text', PARAM_RAW); // no XSS prevention here, users must be trusted
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php // $Id$
+ // block.php - created with Moodle 2.0 dev
+
+$string['appearsinsubcontexts'] = 'Appears in sub-contexts';
+$string['anypagematchingtheabove'] = 'Any page matching the above';
+$string['blocksettings'] = 'Block settings';
+$string['bracketfirst'] = '$a (first)';
+$string['bracketlast'] = '$a (last)';
+$string['defaultregion'] = 'Default region';
+$string['defaultweight'] = 'Default weight';
+$string['onthispage'] = 'On this page';
+$string['pagetypes'] = 'Page types';
+$string['region'] = 'Region';
+$string['subpages'] = 'Specific sub-page';
+$string['thisblockbelongsto'] = 'This block belongs to';
+$string['thisspecificpage'] = 'This specific page (page $a)';
+$string['visible'] = 'Visible';
+$string['weight'] = 'Weight';
+$string['wherethisblockappears'] = 'Where this block appears';
--- /dev/null
+<?php // $Id$
+ // theme_standard.php - created with Moodle 2.0 dev
+
+$string['region-side-pre'] = 'Left';
+$string['region-side-post'] = 'Right';
}
}
+ // 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();
}
$contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.parentcontextid $parentcontexttest))";
}
- $pagetypepatterns = $this->matching_page_type_patterns($this->page->pagetype);
+ $pagetypepatterns = matching_page_type_patterns($this->page->pagetype);
list($pagetypepatterntest, $pagetypepatternparams) =
$DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000');
/// Inner workings =============================================================
- /**
- * Given a specific page type, return all the page type patterns that might
- * match it.
- *
- * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'.
- * @return array an array of all the page type patterns that might match this page type.
- */
- protected function matching_page_type_patterns($pagetype) {
- $patterns = array($pagetype, '*');
- $bits = explode('-', $pagetype);
- if (count($bits) == 3 && $bits[0] == 'mod') {
- if ($bits[2] == 'view') {
- $patterns[] = 'mod-*-view';
- } else if ($bits[2] == 'index') {
- $patterns[] = 'mod-*-index';
- }
- }
- while (count($bits) > 0) {
- $patterns[] = implode('-', $bits) . '-*';
- array_pop($bits);
- }
- return $patterns;
- }
-
/**
* Check whether the page blocks have been loaded yet
*
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 class_exists($classname);
}
+/**
+ * Given a specific page type, return all the page type patterns that might
+ * match it.
+ *
+ * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'.
+ * @return array an array of all the page type patterns that might match this page type.
+ */
+function matching_page_type_patterns($pagetype) {
+ $patterns = array($pagetype);
+ $bits = explode('-', $pagetype);
+ if (count($bits) == 3 && $bits[0] == 'mod') {
+ if ($bits[2] == 'view') {
+ $patterns[] = 'mod-*-view';
+ } else if ($bits[2] == 'index') {
+ $patterns[] = 'mod-*-index';
+ }
+ }
+ while (count($bits) > 0) {
+ $patterns[] = implode('-', $bits) . '-*';
+ array_pop($bits);
+ }
+ $patterns[] = '*';
+ return $patterns;
+}
+
/// Functions update the blocks if required by the request parameters ==========
/**
$controls = array();
$actionurl = $page->url->out_action();
- $returnurlparam = '&returnurl=' . urlencode($page->url->out_returnurl());
// 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 . $returnurlparam,
+ '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($page->url->out_returnurl()),
'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'));
}
// Edit config icon.
if ($block->instance_allow_multiple() || $block->instance_allow_config()) {
- $editurl = $CFG->wwwroot . '/blocks/edit.php?block=' . $block->instance->id;
- if (!empty($block->instance->blockpositionid)) {
- $editurl .= '&positionid=' . $block->instance->blockpositionid;
- }
- $controls[] = array('url' => $editurl . $returnurlparam,
+ $controls[] = array('url' => block_edit_url($block, $page)->out(),
'icon' => 't/edit', 'caption' => get_string('configuration'));
}
return $controls;
}
+/**
+ * Get the URL for editing a particular block instance.
+ * @param block_base $block a block object.
+ * @return moodle_url the url.
+ */
+function block_edit_url($block, $page) {
+ global $CFG;
+ $urlparams = array(
+ 'id' => $block->instance->id,
+ 'pagecontextid' => $page->context->id,
+ 'pagetype' => $page->pagetype,
+ 'returnurl' => $page->url->out_returnurl(),
+ );
+ if ($page->subpage) {
+ $urlparams['subpage'] = $page->subpage;
+ }
+ return new moodle_url($CFG->wwwroot . '/blocks/edit.php', $urlparams);
+}
+
/**
* Process any block actions that were specified in the URL.
*
}
}
+ /**
+ * Get the list of all block regions known to this theme in all templates.
+ * @return array internal region name => human readable name.
+ */
+ public function get_all_block_regions() {
+ // Legacy fallback.
+ if (empty($this->layouts)) {
+ return array(
+ 'side-pre' => get_string('region-side-pre', 'theme_standard'),
+ 'side-post' => get_string('region-side-post', 'theme_standard'),
+ );
+ }
+
+ $regions = array();
+ foreach ($this->layouts as $layoutinfo) {
+ $ownertheme = $this->name;
+ if (strpos($layoutinfo['layout'], 'standard:') === 0) {
+ $ownertheme = 'standard';
+ } else if (strpos($layoutinfo['layout'], 'parent:') === 0) {
+ $ownertheme = $this->parent;
+ }
+
+ foreach ($layoutinfo['regions'] as $region) {
+ $regions[$region] = get_string('region-' . $region, 'theme_' . $ownertheme);
+ }
+ }
+ return $regions;
+ }
+
/**
* Helper method used by {@link update_legacy_information()}. Update one entry
* in the $this->pluginsheets array, based on the legacy $property propery.
public function get_loaded_blocks() {
return $this->birecordsbyregion;
}
- public function matching_page_type_patterns($pagetype) {
- return parent::matching_page_type_patterns($pagetype);
- }
}
class block_ablocktype extends block_base {
public function init() {
public function test_matching_page_type_patterns() {
$this->assert(new ArraysHaveSameValuesExpectation(
array('site-index', 'site-index-*', 'site-*', '*')),
- $this->blockmanager->matching_page_type_patterns('site-index'));
+ matching_page_type_patterns('site-index'));
$this->assert(new ArraysHaveSameValuesExpectation(
array('mod-quiz-report-overview', 'mod-quiz-report-overview-*', 'mod-quiz-report-*', 'mod-quiz-*', 'mod-*', '*')),
- $this->blockmanager->matching_page_type_patterns('mod-quiz-report-overview'));
+ matching_page_type_patterns('mod-quiz-report-overview'));
$this->assert(new ArraysHaveSameValuesExpectation(
array('mod-forum-view', 'mod-*-view', 'mod-forum-view-*', 'mod-forum-*', 'mod-*', '*')),
- $this->blockmanager->matching_page_type_patterns('mod-forum-view'));
+ matching_page_type_patterns('mod-forum-view'));
$this->assert(new ArraysHaveSameValuesExpectation(
array('mod-forum-index', 'mod-*-index', 'mod-forum-index-*', 'mod-forum-*', 'mod-*', '*')),
- $this->blockmanager->matching_page_type_patterns('mod-forum-index'));
+ matching_page_type_patterns('mod-forum-index'));
}
}