mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
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:
parent
1150b08264
commit
6b081d2e9f
10
blocks/amd/build/edit.min.js
vendored
Normal file
10
blocks/amd/build/edit.min.js
vendored
Normal 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
|
1
blocks/amd/build/edit.min.js.map
Normal file
1
blocks/amd/build/edit.min.js.map
Normal 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
59
blocks/amd/src/edit.js
Normal 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();
|
||||
});
|
||||
};
|
46
blocks/classes/external/fetch_addable_blocks.php
vendored
46
blocks/classes/external/fetch_addable_blocks.php
vendored
@ -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.'
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
}
|
||||
|
4
lib/amd/build/addblockmodal.min.js
vendored
4
lib/amd/build/addblockmodal.min.js
vendored
@ -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
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
18
lib/form/classes/external/dynamic_form.php
vendored
18
lib/form/classes/external/dynamic_form.php
vendored
@ -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
|
||||
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -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.
|
||||
|
114
lib/pagelib.php
114
lib/pagelib.php
@ -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.
|
||||
|
||||
|
@ -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}}&bui_addblock={{name}}" class="list-group-item list-group-item-action">{{title}}</a>
|
||||
<a href="{{url}}&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">
|
||||
|
@ -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}}
|
||||
|
@ -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
@ -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
|
||||
},
|
||||
|
||||
|
23
lib/yui/src/blocks/js/blocks.js
vendored
23
lib/yui/src/blocks/js/blocks.js
vendored
@ -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: {
|
||||
|
62
lib/yui/src/blocks/js/manager.js
vendored
62
lib/yui/src/blocks/js/manager.js
vendored
@ -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
|
||||
},
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user