MDL-74465 blocks: allow configuration in modal

Introduce 'pagehash' - an identifier that uniquely identifies a page for the user session
This commit is contained in:
Marina Glancy 2023-02-28 16:34:08 +00:00
parent 1150b08264
commit 6b081d2e9f
26 changed files with 611 additions and 362 deletions

10
blocks/amd/build/edit.min.js vendored Normal file
View File

@ -0,0 +1,10 @@
define("core_block/edit",["exports","core_form/modalform"],(function(_exports,_modalform){var obj;
/**
* Javascript module for editing blocks
*
* @module core_block/edit
* @copyright 2022 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};const SELECTORS_EDITBLOCK='[data-action="editblock"][data-blockid][data-blockform]';_exports.init=pagehash=>{document.addEventListener("click",(e=>{const target=e.target.closest(SELECTORS_EDITBLOCK);if(!target||!target.getAttribute("data-blockform"))return;e.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:target.getAttribute("data-header")},args:{blockid:target.getAttribute("data-blockid"),pagehash:pagehash},formClass:target.getAttribute("data-blockform"),returnFocus:target});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{location.reload()})),modalForm.show()}))}}));
//# sourceMappingURL=edit.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"edit.min.js","sources":["../src/edit.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module for editing blocks\n *\n * @module core_block/edit\n * @copyright 2022 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalForm from 'core_form/modalform';\n\nconst SELECTORS = {\n EDITBLOCK: '[data-action=\"editblock\"][data-blockid][data-blockform]',\n};\n\n/**\n * Initialize module\n * @param {String} pagehash\n */\nexport const init = (pagehash) => {\n document.addEventListener('click', e => {\n const target = e.target.closest(SELECTORS.EDITBLOCK);\n if (!target || !target.getAttribute('data-blockform')) {\n return;\n }\n e.preventDefault();\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: target.getAttribute('data-header'),\n },\n args: {blockid: target.getAttribute('data-blockid'), pagehash},\n formClass: target.getAttribute('data-blockform'),\n returnFocus: target,\n });\n\n // Reload the page when the form is submitted, there is no possibility\n // currently to request contents update of just one block on the page.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n location.reload();\n });\n\n modalForm.show();\n });\n};\n"],"names":["obj","_modalform","__esModule","default","SELECTORS","_exports","init","pagehash","document","addEventListener","e","target","closest","getAttribute","preventDefault","modalForm","ModalForm","modalConfig","title","args","blockid","formClass","returnFocus","events","FORM_SUBMITTED","location","reload","show"],"mappings":"0FAuB4C,IAAAA;;;;;;;kFAA5CC,YAA4CD,IAA5CC,aAA4CD,IAAAE,WAAAF,IAAAG,CAAAA,QAAAH,KAE5C,MAAMI,oBACS,0DAgCbC,SAAAC,KAzBmBC,WACjBC,SAASC,iBAAiB,SAASC,IAC/B,MAAMC,OAASD,EAAEC,OAAOC,QAAQR,qBAChC,IAAKO,SAAWA,OAAOE,aAAa,kBAChC,OAEJH,EAAEI,iBAEF,MAAMC,UAAY,IAAIC,WAAAA,QAAU,CAC5BC,YAAa,CACTC,MAAOP,OAAOE,aAAa,gBAE/BM,KAAM,CAACC,QAAST,OAAOE,aAAa,gBAAiBN,mBACrDc,UAAWV,OAAOE,aAAa,kBAC/BS,YAAaX,SAKjBI,UAAUN,iBAAiBM,UAAUQ,OAAOC,gBAAgB,KACxDC,SAASC,QAAQ,IAGrBX,UAAUY,MAAM,GAClB,CACJ"}

59
blocks/amd/src/edit.js Normal file
View File

@ -0,0 +1,59 @@
// 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/>.
/**
* Javascript module for editing blocks
*
* @module core_block/edit
* @copyright 2022 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ModalForm from 'core_form/modalform';
const SELECTORS = {
EDITBLOCK: '[data-action="editblock"][data-blockid][data-blockform]',
};
/**
* Initialize module
* @param {String} pagehash
*/
export const init = (pagehash) => {
document.addEventListener('click', e => {
const target = e.target.closest(SELECTORS.EDITBLOCK);
if (!target || !target.getAttribute('data-blockform')) {
return;
}
e.preventDefault();
const modalForm = new ModalForm({
modalConfig: {
title: target.getAttribute('data-header'),
},
args: {blockid: target.getAttribute('data-blockid'), pagehash},
formClass: target.getAttribute('data-blockform'),
returnFocus: target,
});
// Reload the page when the form is submitted, there is no possibility
// currently to request contents update of just one block on the page.
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {
location.reload();
});
modalForm.show();
});
};

View File

@ -44,6 +44,7 @@ class fetch_addable_blocks extends external_api {
'pagetype' => new external_value(PARAM_ALPHANUMEXT, 'The type of the page.'),
'pagelayout' => new external_value(PARAM_ALPHA, 'The layout of the page.'),
'subpage' => new external_value(PARAM_TEXT, 'The subpage identifier', VALUE_DEFAULT, ''),
'pagehash' => new external_value(PARAM_ALPHANUMEXT, 'Page hash', VALUE_DEFAULT, ''),
]
);
}
@ -55,9 +56,11 @@ class fetch_addable_blocks extends external_api {
* @param string $pagetype The type of the page
* @param string $pagelayout The layout of the page
* @param string $subpage The subpage identifier
* @param string $pagehash Page hash that can be provided instead of all parameters above
* @return array The blocks list
*/
public static function execute(int $pagecontextid, string $pagetype, string $pagelayout, string $subpage = ''): array {
public static function execute(int $pagecontextid, string $pagetype, string $pagelayout,
string $subpage = '', string $pagehash = ''): array {
global $PAGE;
$params = self::validate_parameters(self::execute_parameters(),
@ -66,28 +69,43 @@ class fetch_addable_blocks extends external_api {
'pagetype' => $pagetype,
'pagelayout' => $pagelayout,
'subpage' => $subpage,
'pagehash' => $pagehash,
]
);
$context = \context::instance_by_id($params['pagecontextid']);
// Validate the context. This will also set the context in $PAGE.
self::validate_context($context);
if ($params['pagehash']) {
// If pagehash is specified, all other parameters are ignored, all information
// about the page is stored in the session.
// We need to manually set the page layout and page type.
$PAGE->set_pagelayout($params['pagelayout']);
$PAGE->set_pagetype($params['pagetype']);
$PAGE->set_subpage($params['subpage']);
$page = \moodle_page::retrieve_edited_page($params['pagehash'], MUST_EXIST);
self::validate_context($page->context);
} else {
// For backward-compatibility and Mobile App instead of pagehash
// we can specify context, pagelayout, pagetype and subtype.
$context = \context::instance_by_id($params['pagecontextid']);
// Validate the context. This will also set the context in $PAGE.
self::validate_context($context);
// We need to manually set the page layout and page type.
$PAGE->set_pagelayout($params['pagelayout']);
$PAGE->set_pagetype($params['pagetype']);
$PAGE->set_subpage($params['subpage']);
$page = $PAGE;
}
// Firstly, we need to load all currently existing page blocks to later determine which blocks are addable.
$PAGE->blocks->load_blocks(false);
$PAGE->blocks->create_all_block_instances();
$page->blocks->load_blocks(false);
$page->blocks->create_all_block_instances();
$addableblocks = $PAGE->blocks->get_addable_blocks();
$addableblocks = $page->blocks->get_addable_blocks();
return array_map(function($block) {
return array_map(function($block) use ($page) {
$classname = \block_manager::get_block_edit_form_class($block->name);
return [
'name' => $block->name,
'title' => get_string('pluginname', "block_{$block->name}")
'title' => get_string('pluginname', "block_{$block->name}"),
'blockform' => $classname::display_form_when_adding() ? $classname : null,
];
}, $addableblocks);
}
@ -103,6 +121,8 @@ class fetch_addable_blocks extends external_api {
[
'name' => new external_value(PARAM_PLUGIN, 'The name of the block.'),
'title' => new external_value(PARAM_RAW, 'The title of the block.'),
'blockform' => new external_value(PARAM_RAW,
'If this block type has a form when it is being added then the classname of the form')
]
),
'List of addable blocks in a given page.'

View File

@ -17,7 +17,7 @@
/**
* 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
* It works with the {@see block_edit_form} class, or rather the particular
* subclass defined by this block, to do the editing.
*
* @package core_block
@ -25,30 +25,27 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once($CFG->libdir . '/formslib.php');
require_once($CFG->libdir . '/blocklib.php');
/**
* The base class form used by blocks/edit.php to edit block instance configuration.
*
* @property-read block_base $block
* @property-read moodle_page $page
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_edit_form extends moodleform {
class block_edit_form extends \core_form\dynamic_form {
/**
* The block instance we are editing.
* @var block_base
*/
public $block;
private $_block;
/**
* The page we are editing this block in association with.
* @var moodle_page
*/
public $page;
private $_page;
/**
* Defaults set in set_data() that need to be returned in get_data() if form elements were not created
@ -56,19 +53,95 @@ class block_edit_form extends moodleform {
*/
protected $defaults = [];
function __construct($actionurl, $block, $page) {
global $CFG;
$this->block = $block;
$this->page = $page;
parent::__construct($actionurl);
/**
* Magic getter for backward compatibility
*
* @param string $name
* @return block_base|moodle_page
*/
public function __get(string $name) {
if ($name === 'page') {
return $this->get_page();
} else if ($name === 'block') {
return $this->get_block();
} else {
throw new coding_exception('Property '.$name.' does not exist');
}
}
/**
* Page where we are adding or editing the block
*
* To access you can also use magic property $this->page
*
* @return moodle_page
* @throws moodle_exception
*/
protected function get_page(): moodle_page {
if (!$this->_page && !empty($this->_customdata['page'])) {
$this->_page = $this->_customdata['page'];
} else if (!$this->_page) {
if (!$pagehash = $this->optional_param('pagehash', '', PARAM_ALPHANUMEXT)) {
throw new \moodle_exception('missingparam', '', '', 'pagehash');
}
$this->_page = moodle_page::retrieve_edited_page($pagehash, MUST_EXIST);
$this->_page->blocks->load_blocks();
}
return $this->_page;
}
/**
* Instance of the block that is being added or edited
*
* To access you can also use magic property $this->block
*
* If {{@see self::display_form_when_adding()}} returns true and the configuration
* form is displayed when adding block, the $this->block->id will be null.
*
* @return block_base
* @throws block_not_on_page_exception
* @throws moodle_exception
*/
protected function get_block(): block_base {
if (!$this->_block && !empty($this->_customdata['block'])) {
$this->_block = $this->_customdata['block'];
} else if (!$this->_block) {
$blockid = $this->optional_param('blockid', null, PARAM_INT);
$blockname = $this->optional_param('blockname', null, PARAM_PLUGIN);
if ($blockname && !$blockid) {
$this->_block = block_instance($blockname);
$this->_block->page = $this->page;
$this->_block->context = $this->page->context;
$this->_block->instance = (object)['parentcontextid' => $this->page->context->id, 'id' => null];
} else {
$this->_block = $this->page->blocks->find_instance($blockid);
}
}
return $this->_block;
}
/**
* Form definition
*/
function definition() {
$mform =& $this->_form;
$mform->addElement('hidden', 'blockid', $this->block->instance->id);
$mform->setType('blockid', PARAM_INT);
$mform->addElement('hidden', 'blockname', $this->optional_param('blockname', null, PARAM_PLUGIN));
$mform->setType('blockname', PARAM_PLUGIN);
$mform->addElement('hidden', 'blockregion', $this->optional_param('blockregion', null, PARAM_TEXT));
$mform->setType('blockregion', PARAM_TEXT);
$mform->addElement('hidden', 'pagehash', $this->optional_param('pagehash', null, PARAM_ALPHANUMEXT));
$mform->setType('pagehash', PARAM_ALPHANUMEXT);
// First show fields specific to this type of block.
$this->specific_definition($mform);
if (!$this->block->instance->id) {
return;
}
// Then show the fields about where this block appears.
$mform->addElement('header', 'whereheader', get_string('wherethisblockappears', 'block'));
@ -110,10 +183,10 @@ class block_edit_form extends moodleform {
// First of all, check if we are editing blocks @ front-page or no and
// make some dark magic if so (MDL-30340) because each page context
// implies one (and only one) harcoded page-type that will be set later
// when processing the form data at {@link block_manager::process_url_edit()}
// when processing the form data at {@see block_manager::process_url_edit()}.
// Front page, show the page-contexts element and set $pagetypelist to 'any page' (*)
// as unique option. Processign the form will do any change if needed
// as unique option. Processign the form will do any change if needed.
if ($this->is_editing_the_frontpage()) {
$contextoptions = array();
$contextoptions[BUI_CONTEXTS_FRONTPAGE_ONLY] = get_string('showonfrontpageonly', 'block');
@ -232,7 +305,9 @@ class block_edit_form extends moodleform {
$mform->hardFreeze($pagefields);
}
$this->add_action_buttons();
if (!empty($this->_customdata['actionbuttons'])) {
$this->add_action_buttons();
}
}
/**
@ -248,13 +323,19 @@ class block_edit_form extends moodleform {
return ($ctxconditions && $issiteindex);
}
function set_data($defaults) {
/**
* Prepare block configuration data and add default values when needed
*
* @param stdClass $defaults
* @return stdClass
*/
protected function prepare_defaults(stdClass $defaults): stdClass {
// Prefix bui_ on all the core field names.
$blockfields = array('showinsubcontexts', 'pagetypepattern', 'subpagepattern', 'parentcontextid',
'defaultregion', 'defaultweight', 'visible', 'region', 'weight');
foreach ($blockfields as $field) {
$newname = 'bui_' . $field;
$defaults->$newname = $defaults->$field;
$defaults->$newname = $defaults->$field ?? null;
}
// Copy block config into config_ fields.
@ -284,7 +365,17 @@ class block_edit_form extends moodleform {
'bui_pagetypepattern' => $defaults->bui_pagetypepattern,
'bui_subpagepattern' => $defaults->bui_subpagepattern,
];
parent::set_data($defaults);
return $defaults;
}
/**
* Load in existing data as form defaults
*
* @param stdClass $defaults
* @return void
*/
public function set_data($defaults) {
parent::set_data($this->prepare_defaults($defaults));
}
/**
@ -299,7 +390,7 @@ class block_edit_form extends moodleform {
* Return submitted data if properly submitted or returns NULL if validation fails or
* if there is no submitted data.
*
* @return object submitted data; NULL if not valid or not submitted or cancelled
* @return stdClass submitted data; NULL if not valid or not submitted or cancelled
*/
public function get_data() {
if ($data = parent::get_data()) {
@ -310,4 +401,85 @@ class block_edit_form extends moodleform {
}
return $data;
}
/**
* Returns context where this form is used
*
* @return context
*/
protected function get_context_for_dynamic_submission(): context {
return $this->page->context;
}
/**
* Checks if current user has access to this form, otherwise throws exception
*/
protected function check_access_for_dynamic_submission(): void {
if ($this->block->instance->id) {
if (!$this->page->user_can_edit_blocks() && !$this->block->user_can_edit()) {
throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock'));
}
} else {
if (!$this->page->user_can_edit_blocks()) {
throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('addblock'));
}
$addableblocks = $this->page->blocks->get_addable_blocks();
$blocktype = $this->block->name();
if (!array_key_exists($blocktype, $addableblocks)) {
throw new moodle_exception('cannotaddthisblocktype', '', $this->page->url->out(), $blocktype);
}
}
}
/**
* Process the form submission, used if form was submitted via AJAX
*/
public function process_dynamic_submission() {
if ($this->block->instance->id) {
$this->page->blocks->save_block_data($this->block, $this->get_data());
} else {
$blockregion = $this->optional_param('blockregion', null, PARAM_TEXT);
$newblock = $this->page->blocks->add_block_at_end_of_default_region($this->block->name(),
empty($blockregion) ? null : $blockregion);
$this->page->blocks->load_blocks();
$newblock = $this->page->blocks->find_instance($newblock->instance->id);
$newdata = $this->prepare_defaults($newblock->instance);
foreach ($this->get_data() as $key => $value) {
$newdata->$key = $value;
}
$this->page->blocks->save_block_data($newblock, $newdata);
}
}
/**
* Load in existing data as form defaults
*/
public function set_data_for_dynamic_submission(): void {
$this->set_data($this->block->instance);
}
/**
* Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
*
* @return moodle_url
*/
protected function get_page_url_for_dynamic_submission(): moodle_url {
return $this->page->url;
}
/**
* Display the configuration form when block is being added to the page
*
* By default when block is added to the page it is added with the default configuration.
* Some block may require configuration, for example, "glossary random entry" block
* needs a glossary to be selected, "RSS feed" block needs an RSS feed to be selected, etc.
*
* Such blocks can override this function and return true. These blocks must
* ensure that the function specific_definition() will work if there is no current block id.
*
* @return bool
*/
public static function display_form_when_adding(): bool {
return false;
}
}

View File

@ -26,6 +26,7 @@
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
use Behat\Gherkin\Node\TableNode as TableNode;
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
@ -56,6 +57,48 @@ class behat_blocks extends behat_base {
}
}
/**
* Adds the selected block to the specified region
*
* Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block to the "(?P<region_string>(?:[^"]|\\")*)" region$/
* @param string $blockname
* @param string $region
*/
public function i_add_the_block_to_the_region(string $blockname, string $region) {
if (!$this->running_javascript()) {
throw new coding_exception('Adding block to specific region is not possible with Javascript disabled');
}
if ($region === "default") {
$region = "";
}
$csselement = 'a[data-key="addblock"][data-blockregion='.behat_context_helper::escape($region).']';
$addblock = get_string('addblock');
$this->execute('behat_general::i_click_on', [$csselement, 'css_element']);
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
}
/**
* Adds the selected block to the specified region and fills configuration form.
*
* Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block to the (?P<region_string>(?:[^"]|\\")*) region with:$/
* @param string $blockname
* @param string $region
* @param TableNode $data
*/
public function i_add_the_block_to_the_region_with(string $blockname, string $region, TableNode $data) {
$blocklabel = get_string('textellipsis', 'moodle', $blockname);
$this->execute('behat_blocks::i_add_the_block_to_the_region', [$blocklabel, $region]);
$this->wait_for_pending_js();
$dialogname = get_string('addblock', 'core_block', $blockname);
$this->execute('behat_forms::i_set_the_following_fields_in_container_to_these_values',
[$dialogname, "dialogue", $data]);
$this->execute('behat_general::i_click_on_in_the', ["Save changes", 'button', $dialogname, 'dialogue']);
}
/**
* Adds the selected block if it is not already present. Editing mode must be previously enabled.
*

View File

@ -1,6 +1,18 @@
This files describes API changes in /blocks/* - activity modules,
information provided here is intended especially for developers.
=== 4.1 ===
* Block configuration form is now displayed in a modal. Class 'block_edit_form' now extends
'\core_form\dynamic_form' and properties $block and $page are read-only. Normally
no changes should be necessary to keep the old behavior of configuration form.
* Block plugins can specify that they want to display configuration form when block is
added to the page by overriding static method block_edit_form::display_form_when_adding().
* Web service 'core_block_fetch_addable_blocks' accepts new parameter 'pagehash'
* Functions in the JS modules 'core/addblockmodal' and 'moodle-core-blockdraganddrop'
have changed their parameters. File lib/ajax/blocks.php takes different arguments.
No backward-compatibility is provided since these files are not part of the blocks API
and not intended to be used by plugins.
=== 4.0 ===
* Block block_quiz_results has been completely removed from core.

View File

@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['addblock'] = 'Add {$a} block';
$string['anypagematchingtheabove'] = 'Any page matching the above';
$string['appearsinsubcontexts'] = 'Appears in sub-contexts';
$string['assignrolesinblock'] = 'Assign roles in {$a} block';

View File

@ -240,6 +240,7 @@ $string['duplicateparaminsql'] = 'ERROR: duplicate parameter name in query';
$string['duplicaterolename'] = 'There is already a role with this name!';
$string['duplicateroleshortname'] = 'There is already a role with this short name!';
$string['duplicateusername'] = 'Duplicate username - skipping record';
$string['editedpagenotfound'] = 'Could not determine the current page. Please try refreshing the page and repeating the operation.';
$string['emailfail'] = 'Emailing failed';
$string['encryption_encryptfailed'] = 'Encryption failed';
$string['encryption_decryptfailed'] = 'Decryption failed';

View File

@ -26,52 +26,29 @@ define('AJAX_SCRIPT', true);
require_once(__DIR__ . '/../../config.php');
// Initialise ALL common incoming parameters here, up front.
$courseid = required_param('courseid', PARAM_INT);
$pagelayout = required_param('pagelayout', PARAM_ALPHAEXT);
$pagetype = required_param('pagetype', PARAM_ALPHANUMEXT);
$contextid = required_param('contextid', PARAM_INT);
$subpage = optional_param('subpage', '', PARAM_ALPHANUMEXT);
$cmid = optional_param('cmid', null, PARAM_INT);
$pagehash = required_param('pagehash', PARAM_RAW);
$action = optional_param('action', '', PARAM_ALPHA);
// Params for blocks-move actions.
$buimoveid = optional_param('bui_moveid', 0, PARAM_INT);
$buinewregion = optional_param('bui_newregion', '', PARAM_ALPHAEXT);
$buibeforeid = optional_param('bui_beforeid', 0, PARAM_INT);
// Setting pagetype and URL.
$PAGE->set_pagetype($pagetype);
$PAGE->set_url('/lib/ajax/blocks.php', array('courseid' => $courseid, 'pagelayout' => $pagelayout, 'pagetype' => $pagetype));
$PAGE->set_url('/lib/ajax/blocks.php', ['pagehash' => $pagehash]);
// Retrieve the edited page from the session hash.
$page = moodle_page::retrieve_edited_page($pagehash, MUST_EXIST);
// Verifying login and session.
$cm = null;
if (!is_null($cmid)) {
$cm = get_coursemodule_from_id(null, $cmid, $courseid, false, MUST_EXIST);
if (!is_null($page->cm)) {
$cm = get_coursemodule_from_id(null, $page->cm->id, $page->course->id, false, MUST_EXIST);
}
require_login($courseid, false, $cm);
require_login($page->course, false, $cm);
require_sesskey();
$PAGE->set_context($page->context);
// Set context from ID, so we don't have to guess it from other info.
$PAGE->set_context(context::instance_by_id($contextid));
// Setting layout to replicate blocks configuration for the page we edit.
$PAGE->set_pagelayout($pagelayout);
$PAGE->set_subpage($subpage);
$PAGE->blocks->add_custom_regions_for_pagetype($pagetype);
$pagetype = explode('-', $pagetype);
switch ($pagetype[0]) {
case 'my':
case 'mycourses':
$PAGE->set_blocks_editing_capability('moodle/my:manageblocks');
break;
case 'user':
if ($pagetype[1] === 'profile' && $PAGE->context->contextlevel == CONTEXT_USER
&& $PAGE->context->instanceid == $USER->id) {
// A user can only move blocks on their own site profile.
$PAGE->set_blocks_editing_capability('moodle/user:manageownblocks');
} else {
$PAGE->set_blocks_editing_capability('moodle/user:manageblocks');
}
break;
if (!$page->user_can_edit_blocks() || !$page->user_is_editing()) {
throw new moodle_exception('nopermissions', '', $page->url->out(), get_string('editblock'));
}
// Send headers.
@ -80,8 +57,8 @@ echo $OUTPUT->header();
switch ($action) {
case 'move':
// Loading blocks and instances for the region.
$PAGE->blocks->load_blocks();
$instances = $PAGE->blocks->get_blocks_for_region($buinewregion);
$page->blocks->load_blocks();
$instances = $page->blocks->get_blocks_for_region($buinewregion);
$buinewweight = null;
if ($buibeforeid == 0) {
@ -121,7 +98,7 @@ switch ($action) {
if (isset($buinewweight)) {
// Nasty hack.
$_POST['bui_newweight'] = $buinewweight;
$PAGE->blocks->process_url_move();
$page->blocks->process_url_move();
}
break;
}

View File

@ -1,10 +1,10 @@
define("core/addblockmodal",["exports","core/modal_factory","core/templates","core/str","core/ajax"],(function(_exports,_modal_factory,_templates,_str,_ajax){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
define("core/addblockmodal",["exports","core/modal_factory","core/templates","core/str","core/ajax","core_form/modalform"],(function(_exports,_modal_factory,_templates,_str,_ajax,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Show an add block modal instead of doing it on a separate page.
*
* @module core/addblockmodal
* @copyright 2016 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax);const SELECTORS_ADD_BLOCK='[data-key="addblock"]';let listenerEventsRegistered=!1;const registerListenerEvents=(pageType,pageLayout,addBlockUrl,subPage)=>{document.addEventListener("click",(e=>{const addBlock=e.target.closest(SELECTORS_ADD_BLOCK);if(addBlock){e.preventDefault();let addBlockModal=null,addBlockModalUrl=null!=addBlockUrl?addBlockUrl:addBlock.dataset.url;buildAddBlockModal().then((modal=>{addBlockModal=modal;const modalBody=renderBlocks(addBlockModalUrl,pageType,pageLayout,subPage);return modal.setBody(modalBody),modal.show(),modalBody})).catch((()=>{addBlockModal.destroy()}))}}))},buildAddBlockModal=()=>_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:(0,_str.get_string)("addblock")}),renderBlocks=async(addBlockUrl,pageType,pageLayout,subPage)=>{const blocks=await getAddableBlocks(pageType,pageLayout,subPage);return _templates.default.render("core/add_block_body",{blocks:blocks,url:addBlockUrl})},getAddableBlocks=async(pageType,pageLayout,subPage)=>{const request={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:M.cfg.contextid,pagetype:pageType,pagelayout:pageLayout,subpage:subPage}};return _ajax.default.call([request])[0]};_exports.init=function(pageType,pageLayout){let addBlockUrl=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,subPage=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";listenerEventsRegistered||(registerListenerEvents(pageType,pageLayout,addBlockUrl,subPage),listenerEventsRegistered=!0)}}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_ajax=_interopRequireDefault(_ajax),_modalform=_interopRequireDefault(_modalform);const SELECTORS_ADD_BLOCK='[data-key="addblock"]',SELECTORS_SHOW_BLOCK_FORM='[data-action="showaddblockform"][data-blockname][data-blockform]';let listenerEventsRegistered=!1;const registerListenerEvents=(addBlockUrl,pagehash)=>{let addBlockModal=null;document.addEventListener("click",(e=>{const showAddBlockForm=e.target.closest(SELECTORS_SHOW_BLOCK_FORM);if(showAddBlockForm){e.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:(0,_str.get_string)("addblock","core_block",showAddBlockForm.getAttribute("data-blocktitle"))},args:{blockname:showAddBlockForm.getAttribute("data-blockname"),pagehash:pagehash,blockregion:showAddBlockForm.getAttribute("data-blockregion")},formClass:showAddBlockForm.getAttribute("data-blockform"),returnFocus:showAddBlockForm});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{addBlockModal.destroy(),window.location.reload()})),modalForm.show()}const addBlock=e.target.closest(SELECTORS_ADD_BLOCK);if(addBlock){e.preventDefault();let addBlockModalUrl=null!=addBlockUrl?addBlockUrl:addBlock.dataset.url;buildAddBlockModal().then((modal=>{addBlockModal=modal;const modalBody=renderBlocks(addBlockModalUrl,pagehash,addBlock.getAttribute("data-blockregion"));return modal.setBody(modalBody),modal.show(),modalBody})).catch((()=>{addBlockModal.destroy()}))}}))},buildAddBlockModal=()=>_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:(0,_str.get_string)("addblock")}),renderBlocks=async(addBlockUrl,pagehash,region)=>{const blocks=await getAddableBlocks(pagehash);return _templates.default.render("core/add_block_body",{blocks:blocks,url:addBlockUrl,blockregion:region,pagehash:pagehash})},getAddableBlocks=async pagehash=>{const request={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:0,pagetype:"",pagelayout:"",subpage:"",pagehash:pagehash}};return _ajax.default.call([request])[0]};_exports.init=function(){let addBlockUrl=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,pagehash=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";listenerEventsRegistered||(registerListenerEvents(addBlockUrl,pagehash),listenerEventsRegistered=!0)}}));
//# sourceMappingURL=addblockmodal.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -25,9 +25,11 @@ import ModalFactory from 'core/modal_factory';
import Templates from 'core/templates';
import {get_string as getString} from 'core/str';
import Ajax from 'core/ajax';
import ModalForm from "core_form/modalform";
const SELECTORS = {
ADD_BLOCK: '[data-key="addblock"]'
ADD_BLOCK: '[data-key="addblock"]',
SHOW_BLOCK_FORM: '[data-action="showaddblockform"][data-blockname][data-blockform]'
};
// Ensure we only add our listeners once.
@ -37,25 +39,47 @@ let listenerEventsRegistered = false;
* Register related event listeners.
*
* @method registerListenerEvents
* @param {String} pageType The type of the page
* @param {String} pageLayout The layout of the page
* @param {String|null} addBlockUrl The add block URL
* @param {String} subPage The subpage identifier
* @param {String} pagehash
*/
const registerListenerEvents = (pageType, pageLayout, addBlockUrl, subPage) => {
const registerListenerEvents = (addBlockUrl, pagehash) => {
let addBlockModal = null;
document.addEventListener('click', e => {
const showAddBlockForm = e.target.closest(SELECTORS.SHOW_BLOCK_FORM);
if (showAddBlockForm) {
e.preventDefault();
const modalForm = new ModalForm({
modalConfig: {
title: getString('addblock', 'core_block',
showAddBlockForm.getAttribute('data-blocktitle')),
},
args: {blockname: showAddBlockForm.getAttribute('data-blockname'), pagehash,
blockregion: showAddBlockForm.getAttribute('data-blockregion')},
formClass: showAddBlockForm.getAttribute('data-blockform'),
returnFocus: showAddBlockForm,
});
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {
addBlockModal.destroy();
window.location.reload();
});
modalForm.show();
}
const addBlock = e.target.closest(SELECTORS.ADD_BLOCK);
if (addBlock) {
e.preventDefault();
let addBlockModal = null;
let addBlockModalUrl = addBlockUrl ?? addBlock.dataset.url;
buildAddBlockModal()
.then(modal => {
addBlockModal = modal;
const modalBody = renderBlocks(addBlockModalUrl, pageType, pageLayout, subPage);
const modalBody = renderBlocks(addBlockModalUrl, pagehash,
addBlock.getAttribute('data-blockregion'));
modal.setBody(modalBody);
modal.show();
@ -86,18 +110,19 @@ const buildAddBlockModal = () => {
*
* @method renderBlocks
* @param {String} addBlockUrl The add block URL
* @param {String} pageType The type of the page
* @param {String} pageLayout The layout of the page
* @param {String} subPage The subpage identifier
* @param {String} pagehash
* @param {String} region
* @return {Promise}
*/
const renderBlocks = async(addBlockUrl, pageType, pageLayout, subPage) => {
const renderBlocks = async(addBlockUrl, pagehash, region) => {
// Fetch all addable blocks in the given page.
const blocks = await getAddableBlocks(pageType, pageLayout, subPage);
const blocks = await getAddableBlocks(pagehash);
return Templates.render('core/add_block_body', {
blocks: blocks,
url: addBlockUrl
url: addBlockUrl,
blockregion: region,
pagehash
});
};
@ -105,19 +130,18 @@ const renderBlocks = async(addBlockUrl, pageType, pageLayout, subPage) => {
* Method that fetches all addable blocks in a given page.
*
* @method getAddableBlocks
* @param {String} pageType The type of the page
* @param {String} pageLayout The layout of the page
* @param {String} subPage The subpage identifier
* @param {String} pagehash
* @return {Promise}
*/
const getAddableBlocks = async(pageType, pageLayout, subPage) => {
const getAddableBlocks = async(pagehash) => {
const request = {
methodname: 'core_block_fetch_addable_blocks',
args: {
pagecontextid: M.cfg.contextid,
pagetype: pageType,
pagelayout: pageLayout,
subpage: subPage,
pagecontextid: 0,
pagetype: '',
pagelayout: '',
subpage: '',
pagehash: pagehash,
},
};
@ -128,14 +152,12 @@ const getAddableBlocks = async(pageType, pageLayout, subPage) => {
* Set up the actions.
*
* @method init
* @param {String} pageType The type of the page
* @param {String} pageLayout The layout of the page
* @param {String|null} addBlockUrl The add block URL
* @param {String} subPage The subpage identifier
* @param {String} addBlockUrl The add block URL
* @param {String} pagehash
*/
export const init = (pageType, pageLayout, addBlockUrl = null, subPage = '') => {
export const init = (addBlockUrl = null, pagehash = '') => {
if (!listenerEventsRegistered) {
registerListenerEvents(pageType, pageLayout, addBlockUrl, subPage);
registerListenerEvents(addBlockUrl, pagehash);
listenerEventsRegistered = true;
}
};

View File

@ -821,6 +821,7 @@ class block_manager {
* @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context.
* @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type.
* @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage.
* @return block_base
*/
public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) {
global $DB;
@ -853,6 +854,13 @@ class block_manager {
if ($block = block_instance($blockname, $blockinstance)) {
$block->instance_create();
}
if (!is_null($this->birecordsbyregion)) {
// If blocks were already loaded on this page, reload them.
$this->birecordsbyregion = null;
$this->load_blocks();
}
return $block;
}
/**
@ -860,11 +868,12 @@ class block_manager {
*
* @param string $blockname Name of the block to add.
* @param null|string $blockregion If defined add the new block to the specified region.
* @return ?block_base
*/
public function add_block_at_end_of_default_region($blockname, $blockregion = null) {
if (empty($this->birecordsbyregion)) {
// No blocks or block regions exist yet.
return;
return null;
}
if ($blockregion === null) {
@ -911,7 +920,7 @@ class block_manager {
// Surely other pages like course-report will need this too, they just are not important
// enough now. This will be decided in the coming days. (MDL-27829, MDL-28150)
$this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage);
return $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage);
}
/**
@ -1335,7 +1344,13 @@ class block_manager {
$editactionurl,
new pix_icon('t/edit', $str, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str,
array('class' => 'editing_edit')
[
'class' => 'editing_edit',
'data-action' => 'editblock',
'data-blockid' => $block->instance->id,
'data-blockform' => self::get_block_edit_form_class($block->name()),
'data-header' => $str,
]
);
}
@ -1654,7 +1669,7 @@ class block_manager {
* @param string $blockname name of the block plugin (without block_ prefix)
* @return string
*/
public static function get_block_edit_form_class(string $blockname) {
public static function get_block_edit_form_class(string $blockname): string {
global $CFG;
require_once("$CFG->dirroot/blocks/moodleblock.class.php");
$blockname = clean_param($blockname, PARAM_PLUGIN);
@ -1776,7 +1791,7 @@ class block_manager {
$classname = self::get_block_edit_form_class($block->name());
/** @var block_edit_form $mform */
$mform = new $classname($editpage->url, $block, $this->page);
$mform = new $classname($editpage->url->out(false), ['page' => $this->page, 'block' => $block, 'actionbuttons' => true]);
$mform->set_data($block->instance);
if ($mform->is_cancelled()) {
@ -1815,8 +1830,9 @@ class block_manager {
*
* @param block_base $block
* @param stdClass $data data from the block edit form
* @return void
*/
public function save_block_data(block_base $block, stdClass $data) {
public function save_block_data(block_base $block, stdClass $data): void {
global $DB;
$bi = new stdClass;

View File

@ -60,6 +60,8 @@ class dynamic_form extends external_api {
$formclass = $params['form'];
parse_str($params['formdata'], $formdata);
self::autoload_block_edit_form($formclass);
if (!class_exists($formclass) || !is_subclass_of($formclass, \core_form\dynamic_form::class)) {
// For security reason we don't throw exception "class does not exist" but rather an access exception.
throw new \moodle_exception('nopermissionform', 'core_form');
@ -85,6 +87,22 @@ class dynamic_form extends external_api {
return $output;
}
/**
* Special autoloading for block forms.
*
* @param string $formclass
* @return void
*/
protected static function autoload_block_edit_form(string $formclass): void {
global $CFG;
if (preg_match('/^block_([\w_]+)_edit_form$/', $formclass, $matches)) {
\block_manager::get_block_edit_form_class($matches[1]);
}
if ($formclass === 'block_edit_form') {
require_once($CFG->dirroot . '/blocks/edit_form.php');
}
}
/**
* Return for modal
* @return external_single_structure

View File

@ -4230,7 +4230,7 @@ class flat_navigation extends navigation_node_collection {
$addblockurl = "?{$url->get_query_string(false)}";
$PAGE->requires->js_call_amd('core/addblockmodal', 'init',
[$PAGE->pagetype, $PAGE->pagelayout, $addblockurl]);
[$addblockurl, $this->page->get_edited_page_hash()]);
}
}

View File

@ -5088,9 +5088,8 @@ EOD;
[
'link' => $url->out(false),
'escapedlink' => "?{$url->get_query_string(false)}",
'pageType' => $this->page->pagetype,
'pageLayout' => $this->page->pagelayout,
'subPage' => $this->page->subpage,
'pagehash' => $this->page->get_edited_page_hash(),
'blockregion' => $region,
]
);
}

View File

@ -371,12 +371,8 @@ class page_requirements_manager {
// Include block drag/drop if editing is on
if ($page->user_is_editing()) {
$params = array(
'courseid' => $page->course->id,
'pagetype' => $page->pagetype,
'pagelayout' => $page->pagelayout,
'subpage' => $page->subpage,
'regions' => $page->blocks->get_regions(),
'contextid' => $page->context->id,
'pagehash' => $page->get_edited_page_hash(),
);
if (!empty($page->cm->id)) {
$params['cmid'] = $page->cm->id;
@ -387,6 +383,7 @@ class page_requirements_manager {
'emptydragdropregion'),
'moodle');
$page->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
$page->requires->js_call_amd('core_block/edit', 'init', ['pagehash' => $page->get_edited_page_hash()]);
}
// Include the YUI CSS Modules.

View File

@ -1637,6 +1637,120 @@ class moodle_page {
throw new coding_exception('verify_https_required() cannot be used anymore.');
}
/**
* Allows to 'serialize' the edited page information and store it in the session cache
*
* Due to Moodle architectural decision and non-SPA approach, a lot of page setup is
* happening in the actual page php file, for example, setting course/cm/context,
* setting layout and pagetype, requiring capabilities, setting specific block editing
* capabilities.
*
* When storing this information in the session cache we can pass the pagehash (cache key)
* as an argument to web services in AJAX requests and retrieve all data associated with
* the page without actually executing PHP code on that page.
*
* @return string|null
*/
public function get_edited_page_hash(): ?string {
global $SESSION;
if (!$this->user_is_editing()) {
return null;
}
$url = new moodle_url($this->url);
$url->set_anchor(null);
$data = [
'contextid' => $this->context->id,
'url' => $url->out_as_local_url(false),
];
if (($cm = $this->cm) && $cm->id) {
$data['cmid'] = $cm->id;
} else if (($course = $this->course) && $course->id) {
$data['courseid'] = $course->id;
}
$keys = ['pagelayout', 'pagetype', 'subpage'];
foreach ($keys as $key) {
if ("{$this->$key}" !== "") {
$data[$key] = $this->$key;
}
}
if ($this->_blockseditingcap !== 'moodle/site:manageblocks') {
$data['bcap'] = $this->_blockseditingcap;
}
if (!empty($this->_othereditingcaps)) {
$data['caps'] = $this->_othereditingcaps;
}
if ($this->_forcelockallblocks) {
$data['forcelock'] = true;
}
$hash = md5(json_encode($data + ['sesskey' => sesskey()]));
$SESSION->editedpages = ($SESSION->editedpages ?? []);
$SESSION->editedpages[$hash] = $data;
return $hash;
}
/**
* Retrieves a page that is being edited from the session cache
*
* {@see self::get_edited_page_hash()}
*
* @param string $hash
* @param int $strictness
* @return self|null
*/
public static function retrieve_edited_page(string $hash, $strictness = IGNORE_MISSING): ?self {
global $CFG, $SESSION;
$data = $SESSION->editedpages[$hash] ?? null;
if (!$data || !is_array($data)
|| $hash !== md5(json_encode($data + ['sesskey' => sesskey()]))) {
// This can happen if the session cache becomes corrupt or the user logged out and back
// in in another window and changed their session. Refreshing the page will generate
// and store the correct page hash.
if ($strictness === MUST_EXIST) {
throw new moodle_exception('editedpagenotfound');
}
return null;
}
if (!empty($CFG->moodlepageclass)) {
if (!empty($CFG->moodlepageclassfile)) {
require_once($CFG->moodlepageclassfile);
}
$classname = $CFG->moodlepageclass;
} else {
$classname = self::class;
}
/** @var moodle_page $page */
$page = new $classname();
$page->set_context(context::instance_by_id($data['contextid']));
if (array_key_exists('cmid', $data)) {
[$course, $cm] = get_course_and_cm_from_cmid($data['cmid']);
$page->set_cm($cm, $course);
} else if (array_key_exists('courseid', $data)) {
$page->set_course(get_course($data['courseid']));
}
$page->set_url(new moodle_url($data['url']));
$keys = ['pagelayout', 'pagetype', 'subpage'];
foreach ($keys as $key) {
if (array_key_exists($key, $data)) {
$func = "set_{$key}";
$page->$func($data[$key]);
}
}
if (array_key_exists('bcap', $data)) {
$page->set_blocks_editing_capability($data['bcap']);
}
if (array_key_exists('caps', $data)) {
foreach ($data['caps'] as $cap) {
$page->set_other_editing_capability($cap);
}
}
if (array_key_exists('forcelock', $data)) {
$page->force_lock_all_blocks();
}
$page->blocks->add_custom_regions_for_pagetype($page->pagetype);
return $page;
}
// Initialisation methods =====================================================
// These set various things up in a default way.

View File

@ -25,14 +25,20 @@
Example context (json):
{
"blocks" : [ { "name": "test", "title": "Test block" } ],
"blocks" : [
{ "name": "test", "title": "Test block" },
{ "name": "html", "title": "Block with form", "blockform": "block_edit_form" }
],
"url" : "?a=b"
}
}}
<div class="list-group">
{{#blocks}}
<a href="{{url}}&amp;bui_addblock={{name}}" class="list-group-item list-group-item-action">{{title}}</a>
<a href="{{url}}&amp;bui_addblock={{name}}" class="list-group-item list-group-item-action"
data-blockname="{{name}}" data-blocktitle="{{title}}" data-blockregion="{{blockregion}}"
{{#blockform}}data-action="showaddblockform" data-blockform="{{blockform}}"{{/blockform}}
>{{#blockform}}{{#str}}textellipsis, moodle, {{title}}{{/str}}{{/blockform}}{{^blockform}}{{title}}{{/blockform}}</a>
{{/blocks}}
{{^blocks}}
<div class="alert alert-primary" role="alert">

View File

@ -23,14 +23,14 @@
{
"link" : "/my/index.php?bui_addblock&bui_blockregion=content&sesskey=M3mes",
"escapedlink" : "?bui_addblock&bui_blockregion=content&sesskey=M3mes",
"pageType" : "my-index",
"pageLayout" : "mydashboard",
"subPage": "15"
"pagehash": "abcdefgh",
"blockregion": "side-pre"
}
}}
<div class="add_block_button">
<a href="{{link}}" id="addblock-{{uniqid}}" class="btn btn-link block-add text-left mb-3" data-key="addblock" data-url="{{escapedlink}}">
<a href="{{link}}" id="addblock-{{uniqid}}" class="btn btn-link block-add text-left mb-3" data-key="addblock"
data-url="{{escapedlink}}" data-blockregion="{{blockregion}}">
<i class="fa fa-plus py-2 mr-3" aria-hidden="true"></i>{{#str}}addblock{{/str}}
</a>
</div>
@ -38,6 +38,6 @@
{{#js}}
// Initialise the JS for the modal window which displays the blocks available to add.
require(['core/addblockmodal'], function(addBlockModal) {
addBlockModal.init('{{pageType}}', '{{pageLayout}}', null, '{{subPage}}');
addBlockModal.init(null, '{{pagehash}}');
});
{{/js}}

View File

@ -261,11 +261,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -311,22 +307,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}, {
NAME: 'core-blocks-dragdrop',
ATTRS: {
courseid: {
value: null
},
cmid: {
value: null
},
contextid: {
value: null
},
pagelayout: {
value: null
},
pagetype: {
value: null
},
subpage: {
pagehash: {
value: null
},
regions: {
@ -706,11 +687,7 @@ MANAGER.prototype = {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -761,62 +738,12 @@ Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME: 'core-blocks-dragdrop-manager',
ATTRS: {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid: {
value: null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid: {
value: null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid: {
value: null
},
/**
* The current page layout.
* @attribute pagelayout
* The page identifier.
* @attribute pagehash
* @type string|null
* @default null
*/
pagelayout: {
value: null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype: {
value: null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage: {
pagehash: {
value: null
},

File diff suppressed because one or more lines are too long

View File

@ -261,11 +261,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -311,22 +307,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}, {
NAME: 'core-blocks-dragdrop',
ATTRS: {
courseid: {
value: null
},
cmid: {
value: null
},
contextid: {
value: null
},
pagelayout: {
value: null
},
pagetype: {
value: null
},
subpage: {
pagehash: {
value: null
},
regions: {
@ -701,11 +682,7 @@ MANAGER.prototype = {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -756,62 +733,12 @@ Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME: 'core-blocks-dragdrop-manager',
ATTRS: {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid: {
value: null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid: {
value: null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid: {
value: null
},
/**
* The current page layout.
* @attribute pagelayout
* The page identifier.
* @attribute pagehash
* @type string|null
* @default null
*/
pagelayout: {
value: null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype: {
value: null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage: {
pagehash: {
value: null
},

View File

@ -256,11 +256,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -306,22 +302,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
}, {
NAME: 'core-blocks-dragdrop',
ATTRS: {
courseid: {
value: null
},
cmid: {
value: null
},
contextid: {
value: null
},
pagelayout: {
value: null
},
pagetype: {
value: null
},
subpage: {
pagehash: {
value: null
},
regions: {

View File

@ -313,11 +313,7 @@ MANAGER.prototype = {
// Prepare request parameters
var params = {
sesskey: M.cfg.sesskey,
courseid: this.get('courseid'),
pagelayout: this.get('pagelayout'),
pagetype: this.get('pagetype'),
subpage: this.get('subpage'),
contextid: this.get('contextid'),
pagehash: this.get('pagehash'),
action: 'move',
bui_moveid: this.get_block_id(dragnode),
bui_newregion: this.get_block_region(dropnode)
@ -368,62 +364,12 @@ Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, {
NAME: 'core-blocks-dragdrop-manager',
ATTRS: {
/**
* The Course ID if there is one.
* @attribute courseid
* @type int|null
* @default null
*/
courseid: {
value: null
},
/**
* The Course Module ID if there is one.
* @attribute cmid
* @type int|null
* @default null
*/
cmid: {
value: null
},
/**
* The Context ID.
* @attribute contextid
* @type int|null
* @default null
*/
contextid: {
value: null
},
/**
* The current page layout.
* @attribute pagelayout
* The page identifier.
* @attribute pagehash
* @type string|null
* @default null
*/
pagelayout: {
value: null
},
/**
* The page type string, should be used as the id for the body tag in the theme.
* @attribute pagetype
* @type string|null
* @default null
*/
pagetype: {
value: null
},
/**
* The subpage identifier, if any.
* @attribute subpage
* @type string|null
* @default null
*/
subpage: {
pagehash: {
value: null
},