mirror of
https://github.com/moodle/moodle.git
synced 2025-08-09 02:46:40 +02:00
Merge branch 'migration-nov26' of https://github.com/Chocolate-lightning/moodle
This commit is contained in:
commit
d29c09344e
150 changed files with 944 additions and 445 deletions
2
lib/amd/build/addblockmodal.min.js
vendored
2
lib/amd/build/addblockmodal.min.js
vendored
|
@ -1,2 +1,2 @@
|
|||
define ("core/addblockmodal",["exports","core/modal_factory","core/templates","core/str","core/ajax"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=f(b);c=f(c);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function h(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){g(i,d,e,f,h,"next",a)}function h(a){g(i,d,e,f,h,"throw",a)}f(void 0)})}}var i={ADD_BLOCK:"[data-key=\"addblock\"]"},j=null,k=function(a,b,c){document.addEventListener("click",function(d){if(d.target.closest(i.ADD_BLOCK)){d.preventDefault();if(j){j.show()}else{l().then(function(d){j=d;var e=m(c,a,b);d.setBody(e);d.show();return e}).catch(function(){j.destroy();j=null})}}})},l=function(){return b.default.create({type:b.default.types.CANCEL,title:(0,d.get_string)("addblock")})},m=function(){var a=h(regeneratorRuntime.mark(function a(b,d,e){var f;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return n(d,e);case 2:f=a.sent;return a.abrupt("return",c.default.render("core/add_block_body",{blocks:f,url:b}));case 4:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),n=function(){var a=h(regeneratorRuntime.mark(function a(b,c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:M.cfg.contextid,pagetype:b,pagelayout:c}};return a.abrupt("return",e.default.call([d])[0]);case 2:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.init=function init(a,b,c){k(a,b,c)}});
|
||||
define ("core/addblockmodal",["exports","core/modal_factory","core/templates","core/str","core/ajax"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=f(b);c=f(c);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function h(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){g(i,d,e,f,h,"next",a)}function h(a){g(i,d,e,f,h,"throw",a)}f(void 0)})}}var i={ADD_BLOCK:"[data-key=\"addblock\"]"},j=null,k=function(a,b,c){document.addEventListener("click",function(d){if(d.target.closest(i.ADD_BLOCK)){d.preventDefault();if(null===c){c=d.target.closest(i.ADD_BLOCK).dataset.url}if(j){j.show()}else{l().then(function(d){j=d;var e=m(c,a,b);d.setBody(e);d.show();return e}).catch(function(){j.destroy();j=null})}}})},l=function(){return b.default.create({type:b.default.types.CANCEL,title:(0,d.get_string)("addblock")})},m=function(){var a=h(regeneratorRuntime.mark(function a(b,d,e){var f;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return n(d,e);case 2:f=a.sent;return a.abrupt("return",c.default.render("core/add_block_body",{blocks:f,url:b}));case 4:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),n=function(){var a=h(regeneratorRuntime.mark(function a(b,c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d={methodname:"core_block_fetch_addable_blocks",args:{pagecontextid:M.cfg.contextid,pagetype:b,pagelayout:c}};return a.abrupt("return",e.default.call([d])[0]);case 2:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.init=function init(a,b){var c=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;k(a,b,c)}});
|
||||
//# sourceMappingURL=addblockmodal.min.js.map
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -38,7 +38,7 @@ let addBlockModal = null;
|
|||
* @method registerListenerEvents
|
||||
* @param {String} pageType The type of the page
|
||||
* @param {String} pageLayout The layout of the page
|
||||
* @param {String} addBlockUrl The add block URL
|
||||
* @param {String|null} addBlockUrl The add block URL
|
||||
*/
|
||||
const registerListenerEvents = (pageType, pageLayout, addBlockUrl) => {
|
||||
document.addEventListener('click', e => {
|
||||
|
@ -46,6 +46,10 @@ const registerListenerEvents = (pageType, pageLayout, addBlockUrl) => {
|
|||
if (e.target.closest(SELECTORS.ADD_BLOCK)) {
|
||||
e.preventDefault();
|
||||
|
||||
if (addBlockUrl === null) {
|
||||
addBlockUrl = e.target.closest(SELECTORS.ADD_BLOCK).dataset.url;
|
||||
}
|
||||
|
||||
if (addBlockModal) { // The 'add block' modal has been already created.
|
||||
// Display the 'add block' modal.
|
||||
addBlockModal.show();
|
||||
|
@ -128,8 +132,8 @@ const getAddableBlocks = async(pageType, pageLayout) => {
|
|||
* @method init
|
||||
* @param {String} pageType The type of the page
|
||||
* @param {String} pageLayout The layout of the page
|
||||
* @param {String} addBlockUrl The add block URL
|
||||
* @param {String|null} addBlockUrl The add block URL
|
||||
*/
|
||||
export const init = (pageType, pageLayout, addBlockUrl) => {
|
||||
export const init = (pageType, pageLayout, addBlockUrl = null) => {
|
||||
registerListenerEvents(pageType, pageLayout, addBlockUrl);
|
||||
};
|
||||
|
|
|
@ -837,12 +837,23 @@ class block_manager {
|
|||
}
|
||||
}
|
||||
|
||||
public function add_block_at_end_of_default_region($blockname) {
|
||||
/**
|
||||
* When passed a block name create a new instance of the block in the specified region.
|
||||
*
|
||||
* @param string $blockname Name of the block to add.
|
||||
* @param null|string $blockregion If defined add the new block to the specified region.
|
||||
*/
|
||||
public function add_block_at_end_of_default_region($blockname, $blockregion = null) {
|
||||
if (empty($this->birecordsbyregion)) {
|
||||
// No blocks or block regions exist yet.
|
||||
return;
|
||||
}
|
||||
$defaulregion = $this->get_default_region();
|
||||
|
||||
if ($blockregion === null) {
|
||||
$defaulregion = $this->get_default_region();
|
||||
} else {
|
||||
$defaulregion = $blockregion;
|
||||
}
|
||||
|
||||
$lastcurrentblock = end($this->birecordsbyregion[$defaulregion]);
|
||||
if ($lastcurrentblock) {
|
||||
|
@ -1458,6 +1469,8 @@ class block_manager {
|
|||
global $CFG, $PAGE, $OUTPUT;
|
||||
|
||||
$blocktype = optional_param('bui_addblock', null, PARAM_PLUGIN);
|
||||
$blockregion = optional_param('bui_blockregion', null, PARAM_TEXT);
|
||||
|
||||
if ($blocktype === null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1519,7 +1532,7 @@ class block_manager {
|
|||
throw new moodle_exception('cannotaddthisblocktype', '', $this->page->url->out(), $blocktype);
|
||||
}
|
||||
|
||||
$this->add_block_at_end_of_default_region($blocktype);
|
||||
$this->add_block_at_end_of_default_region($blocktype, $blockregion);
|
||||
|
||||
// If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there.
|
||||
$this->page->ensure_param_not_in_url('bui_addblock');
|
||||
|
|
|
@ -58,6 +58,10 @@ class secondary extends view {
|
|||
'outcomes' => 2.2,
|
||||
'coursecompletion' => 6,
|
||||
'filtermanagement' => 9,
|
||||
'unenrolself' => 10,
|
||||
'coursetags' => 11,
|
||||
'download' => 12,
|
||||
'contextlocking' => 13,
|
||||
],
|
||||
];
|
||||
$nodes['navigation'] = [
|
||||
|
|
|
@ -515,6 +515,7 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
|
|||
if ($unenrollink = $plugin->get_unenrolself_link($instance)) {
|
||||
$shortname = format_string($course->shortname, true, array('context' => $coursecontext));
|
||||
$coursenode->add(get_string('unenrolme', 'core_enrol', $shortname), $unenrollink, navigation_node::TYPE_SETTING, null, 'unenrolself', new pix_icon('i/user', ''));
|
||||
$coursenode->get('unenrolself')->set_force_into_more_menu();
|
||||
break;
|
||||
//TODO. deal with multiple unenrol links - not likely case, but still...
|
||||
}
|
||||
|
|
|
@ -844,6 +844,24 @@ class navigation_node implements renderable {
|
|||
return $this->action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array consisting of the additional attributes for the action url.
|
||||
*
|
||||
* @return array Formatted array to parse in a template
|
||||
*/
|
||||
public function actionattributes() {
|
||||
if ($this->action instanceof action_link) {
|
||||
return array_map(function($key, $value) {
|
||||
return [
|
||||
'name' => $key,
|
||||
'value' => $value
|
||||
];
|
||||
}, array_keys($this->action->attributes), $this->action->attributes);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node and its children should be added into a "more" menu whenever possible.
|
||||
*
|
||||
|
@ -4100,27 +4118,8 @@ class flat_navigation extends navigation_node_collection {
|
|||
$flat->icon = new pix_icon('t/preferences', '');
|
||||
$this->add($flat);
|
||||
}
|
||||
|
||||
// Add-a-block in editing mode.
|
||||
if (isset($this->page->theme->addblockposition) &&
|
||||
$this->page->theme->addblockposition == BLOCK_ADDBLOCK_POSITION_FLATNAV &&
|
||||
$PAGE->user_is_editing() && $PAGE->user_can_edit_blocks()) {
|
||||
$url = new moodle_url($PAGE->url, ['bui_addblock' => '', 'sesskey' => sesskey()]);
|
||||
$addablock = navigation_node::create(get_string('addblock'), $url);
|
||||
$flat = new flat_navigation_node($addablock, 0);
|
||||
$flat->set_showdivider(true, get_string('blocksaddedit'));
|
||||
$flat->key = 'addblock';
|
||||
$flat->icon = new pix_icon('i/addblock', '');
|
||||
$this->add($flat);
|
||||
|
||||
$addblockurl = "?{$url->get_query_string(false)}";
|
||||
|
||||
$PAGE->requires->js_call_amd('core/addblockmodal', 'init',
|
||||
[$PAGE->pagetype, $PAGE->pagelayout, $addblockurl]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override the parent so we can set a label for this collection if it has not been set yet.
|
||||
*
|
||||
|
@ -4518,6 +4517,7 @@ class settings_navigation extends navigation_node {
|
|||
if (!$adminoptions->update && $adminoptions->tags) {
|
||||
$url = new moodle_url('/course/tags.php', array('id' => $course->id));
|
||||
$coursenode->add(get_string('coursetags', 'tag'), $url, self::TYPE_SETTING, null, 'coursetags', new pix_icon('i/settings', ''));
|
||||
$coursenode->get('coursetags')->set_force_into_more_menu();
|
||||
}
|
||||
|
||||
// add enrol nodes
|
||||
|
@ -4654,6 +4654,7 @@ class settings_navigation extends navigation_node {
|
|||
|
||||
$coursenode->add($linkattr->displaystring, $actionlink, self::TYPE_SETTING, null, 'download',
|
||||
new pix_icon('t/download', ''));
|
||||
$coursenode->get('download')->set_force_into_more_menu();
|
||||
}
|
||||
|
||||
// Return we are done
|
||||
|
|
41
lib/templates/add_block_button.mustache
Normal file
41
lib/templates/add_block_button.mustache
Normal file
|
@ -0,0 +1,41 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/add_block_button
|
||||
|
||||
Template for the body of the fake 'add block' block.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"link" : "/my/index.php?bui_addblock&bui_blockregion=content&sesskey=M3mes",
|
||||
"escapedlink" : "?bui_addblock&bui_blockregion=content&sesskey=M3mes",
|
||||
"pageType" : "my-index",
|
||||
"pageLayout" : "mydashboard"
|
||||
}
|
||||
|
||||
}}
|
||||
<a href="{{link}}" id="addblock-{{uniqid}}" class="btn btn-link block-add text-left" data-key="addblock" data-url="{{escapedlink}}">
|
||||
{{#str}}addblock{{/str}}
|
||||
<i class="fa fa-plus-square pull-right py-1" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
{{#js}}
|
||||
// Initialise the JS for the modal window which displays the blocks available to add.
|
||||
require(['core/addblockmodal'], function(addBlockModal) {
|
||||
addBlockModal.init('{{pageType}}', '{{pageLayout}}');
|
||||
});
|
||||
{{/js}}
|
|
@ -48,16 +48,10 @@
|
|||
</div>
|
||||
<div class="d-sm-flex align-items-center">
|
||||
{{#contextheader}}
|
||||
<div class="mr-auto">
|
||||
{{{contextheader}}}
|
||||
</div>
|
||||
<div class="mr-auto">
|
||||
{{{contextheader}}}
|
||||
</div>
|
||||
{{/contextheader}}
|
||||
|
||||
{{#settingsmenu}}
|
||||
<div class="context-header-settings-menu">
|
||||
{{{settingsmenu}}}
|
||||
</div>
|
||||
{{/settingsmenu}}
|
||||
<div class="header-actions-container flex-shrink-0" data-region="header-actions-container">
|
||||
{{#headeractions}}
|
||||
<div class="header-action ml-2">{{{.}}}</div>
|
||||
|
|
|
@ -50,12 +50,12 @@
|
|||
{{^haschildren}}
|
||||
<li class="nav-item" role="none" data-forceintomoremenu="{{#forceintomoremenu}}true{{/forceintomoremenu}}{{^forceintomoremenu}}false{{/forceintomoremenu}}">
|
||||
{{#tab}}
|
||||
<a role="menuitem" class="nav-link {{#isactive}}active{{/isactive}} {{#classes}}{{.}} {{/classes}}" href="{{tab}}" data-toggle="tab" data-text="{{{text}}}" aria-current="false" tabindex="-1">
|
||||
<a role="menuitem" class="nav-link {{#isactive}}active{{/isactive}} {{#classes}}{{.}} {{/classes}}" {{#actionattributes}}{{name}}="{{value}}"{{/actionattributes}} href="{{tab}}" data-toggle="tab" data-text="{{{text}}}" aria-current="false" tabindex="-1">
|
||||
{{{text}}}
|
||||
</a>
|
||||
{{/tab}}
|
||||
{{^tab}}
|
||||
<a role="menuitem" class="nav-link {{#isactive}}active{{/isactive}} {{#classes}}{{.}} {{/classes}}" href="{{{url}}}{{{action}}}" {{#isactive}}aria-current="true"{{/isactive}} tabindex="-1">
|
||||
<a role="menuitem" class="nav-link {{#isactive}}active{{/isactive}} {{#classes}}{{.}} {{/classes}}" {{#actionattributes}}{{name}}="{{value}}"{{/actionattributes}} href="{{{url}}}{{{action}}}" {{#isactive}}aria-current="true"{{/isactive}} tabindex="-1">
|
||||
{{{text}}}
|
||||
</a>
|
||||
{{/tab}}
|
||||
|
|
|
@ -36,11 +36,6 @@
|
|||
}
|
||||
}
|
||||
}}
|
||||
{{#secondarynavigation}}
|
||||
<div class="secondary-navigation">
|
||||
{{> core/moremenu}}
|
||||
</div>
|
||||
{{/secondarynavigation}}
|
||||
{{^secondarynavigation}}
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<!-- First the top most node and immediate children -->
|
||||
|
|
|
@ -250,7 +250,8 @@ Feature: Initials bar
|
|||
And I click on "Save changes" "button"
|
||||
And I log out
|
||||
And I am on the "C1" "Course" page logged in as "teacher"
|
||||
And I navigate to "Reports > Activity completion" in current page administration
|
||||
And I navigate to "Reports" in current page administration
|
||||
And I select "Activity completion" from the "Report type" singleselect
|
||||
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
|
||||
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element"
|
||||
And ".page-item.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
|
||||
|
@ -275,7 +276,8 @@ Feature: Initials bar
|
|||
And I should see "Bstudent Astudent"
|
||||
And I should not see "Cstudent Cstudent"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Reports > Activity completion" in current page administration
|
||||
And I navigate to "Reports" in current page administration
|
||||
And I select "Activity completion" from the "Report type" singleselect
|
||||
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
|
||||
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element"
|
||||
And ".page-item.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
|
||||
|
|
|
@ -81,4 +81,18 @@ class behat_deprecated extends behat_base {
|
|||
throw new Exception($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks link with specified id|title|alt|text in the flat navigation drawer.
|
||||
*
|
||||
* @When /^I select "(?P<link_string>(?:[^"]|\\")*)" from flat navigation drawer$/
|
||||
* @throws ElementNotFoundException Thrown by behat_base::find
|
||||
* @param string $link
|
||||
* @deprecated Since Moodle 4.0
|
||||
*/
|
||||
public function i_select_from_flat_navigation_drawer(string $link) {
|
||||
self::deprecated_message(['i_select_from_primary_navigation', 'i_select_from_secondary_navigation'], true);
|
||||
|
||||
$this->i_open_flat_navigation_drawer();
|
||||
$this->execute('behat_general::i_click_on_in_the', [$link, 'link', '#nav-drawer', 'css_element']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -444,7 +444,9 @@ class behat_navigation extends behat_base {
|
|||
$nodetext = end($nodes);
|
||||
|
||||
// Find administration menu.
|
||||
$menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true);
|
||||
if (!$menuxpath = $this->find_page_action_menu()) {
|
||||
$menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true);
|
||||
}
|
||||
|
||||
$this->toggle_page_administration_menu($menuxpath);
|
||||
$this->execute('behat_general::should_exist_in_the', [$nodetext, $selectortype, $menuxpath, 'xpath_element']);
|
||||
|
@ -489,7 +491,7 @@ class behat_navigation extends behat_base {
|
|||
*/
|
||||
public function i_navigate_to_in_site_administration($nodetext) {
|
||||
$nodelist = array_map('trim', explode('>', $nodetext));
|
||||
$this->i_select_from_flat_navigation_drawer(get_string('administrationsite'));
|
||||
$this->i_select_from_primary_navigation(get_string('administrationsite'));
|
||||
$this->select_on_administration_page($nodelist);
|
||||
}
|
||||
|
||||
|
@ -911,15 +913,28 @@ class behat_navigation extends behat_base {
|
|||
}
|
||||
|
||||
/**
|
||||
* Clicks link with specified id|title|alt|text in the flat navigation drawer.
|
||||
* Clicks link with specified id|title|alt|text in the primary navigation
|
||||
*
|
||||
* @When /^I select "(?P<link_string>(?:[^"]|\\")*)" from flat navigation drawer$/
|
||||
* @When /^I select "(?P<link_string>(?:[^"]|\\")*)" from primary navigation$/
|
||||
* @throws ElementNotFoundException Thrown by behat_base::find
|
||||
* @param string $link
|
||||
*/
|
||||
public function i_select_from_flat_navigation_drawer($link) {
|
||||
$this->i_open_flat_navigation_drawer();
|
||||
$this->execute('behat_general::i_click_on_in_the', [$link, 'link', '#nav-drawer', 'css_element']);
|
||||
public function i_select_from_primary_navigation(string $link) {
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
[$link, 'link', '.primary-navigation .moremenu.navigation', 'css_element']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks link with specified id|title|alt|text in the secondary navigation
|
||||
*
|
||||
* @throws ElementNotFoundException Thrown by behat_base::find
|
||||
* @param string $link
|
||||
*/
|
||||
public function i_select_from_secondary_navigation(string $link) {
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
[$link, 'link', '.secondary-navigation .moremenu.navigation', 'css_element']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -928,7 +943,9 @@ class behat_navigation extends behat_base {
|
|||
protected function go_to_main_course_page() {
|
||||
$url = $this->getSession()->getCurrentUrl();
|
||||
if (!preg_match('|/course/view.php\?id=[\d]+$|', $url)) {
|
||||
$node = $this->find('xpath', '//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]');
|
||||
$node = $this->find('xpath',
|
||||
'//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]'
|
||||
);
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
}
|
||||
}
|
||||
|
@ -993,11 +1010,16 @@ class behat_navigation extends behat_base {
|
|||
|
||||
// Find a link and click on it.
|
||||
$linkname = behat_context_helper::escape($lastnode);
|
||||
$xpath .= '//a[contains(normalize-space(.), ' . $linkname . ')]';
|
||||
if (!$node = $this->getSession()->getPage()->find('xpath', $xpath)) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'Link "' . join(' > ', $nodelist) . '"');
|
||||
$xpathlink = $xpathbutton = $xpath;
|
||||
$xpathlink .= '//a[contains(normalize-space(.), ' . $linkname . ')]';
|
||||
$xpathbutton .= '//button[contains(normalize-space(.), ' . $linkname . ')]';
|
||||
if ($node = $this->getSession()->getPage()->find('xpath', $xpathbutton)) {
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
} else if (!$node = $this->getSession()->getPage()->find('xpath', $xpathlink)) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'Link "' . join(' > ', $nodelist) . '"');
|
||||
} else {
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
}
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1007,7 +1029,8 @@ class behat_navigation extends behat_base {
|
|||
* @return null|string
|
||||
*/
|
||||
protected function find_header_administration_menu($mustexist = false) {
|
||||
$menuxpath = '//header[@id=\'page-header\']//div[contains(@class,\'moodle-actionmenu\')]';
|
||||
$menuxpath = '//div[contains(@class,\'secondary-navigation\')]//nav[contains(@class,\'moremenu\')]';
|
||||
|
||||
if ($mustexist) {
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Page header administration menu');
|
||||
$this->find('xpath', $menuxpath, $exception);
|
||||
|
@ -1034,6 +1057,24 @@ class behat_navigation extends behat_base {
|
|||
return $menuxpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the action menu on the page (but not in the header) and returns its xpath
|
||||
*
|
||||
* @param null|bool $mustexist if specified throws an exception if menu is not found
|
||||
* @return null|string
|
||||
*/
|
||||
protected function find_page_action_menu($mustexist = false) {
|
||||
$menuxpath = '//div[@id=\'action-menu-0-menubar\']';
|
||||
|
||||
if ($mustexist) {
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Page check');
|
||||
$this->find('xpath', $menuxpath, $exception);
|
||||
} else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) {
|
||||
return null;
|
||||
}
|
||||
return $menuxpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles administration menu
|
||||
*
|
||||
|
@ -1045,7 +1086,9 @@ class behat_navigation extends behat_base {
|
|||
}
|
||||
if ($menuxpath && $this->running_javascript()) {
|
||||
$node = $this->find('xpath', $menuxpath . '//a[@data-toggle=\'dropdown\']');
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
if ($node->isVisible()) {
|
||||
$this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1062,6 +1105,8 @@ class behat_navigation extends behat_base {
|
|||
// Find administration menu.
|
||||
if ($menuxpath = $this->find_header_administration_menu()) {
|
||||
$isheader = true;
|
||||
} else if ($menuxpath = $this->find_page_action_menu(true)) {
|
||||
$isheader = false;
|
||||
} else {
|
||||
$menuxpath = $this->find_page_administration_menu(true);
|
||||
$isheader = false;
|
||||
|
@ -1069,6 +1114,12 @@ class behat_navigation extends behat_base {
|
|||
|
||||
$this->execute('behat_navigation::toggle_page_administration_menu', [$menuxpath]);
|
||||
|
||||
$firstnode = $nodelist[0];
|
||||
$firstlinkname = behat_context_helper::escape($firstnode);
|
||||
$firstlink = $this->getSession()->getPage()->find('xpath',
|
||||
$menuxpath . '//a[contains(normalize-space(.), ' . $firstlinkname . ')]'
|
||||
);
|
||||
|
||||
if (!$isheader || count($nodelist) == 1) {
|
||||
$lastnode = end($nodelist);
|
||||
$linkname = behat_context_helper::escape($lastnode);
|
||||
|
@ -1077,16 +1128,32 @@ class behat_navigation extends behat_base {
|
|||
$this->execute('behat_general::i_click_on', [$link, 'NodeElement']);
|
||||
return;
|
||||
}
|
||||
} else if ($firstlink) {
|
||||
$this->execute('behat_general::i_click_on', [$firstlink, 'NodeElement']);
|
||||
array_splice($nodelist, 0, 1);
|
||||
$this->select_on_administration_page($nodelist);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($isheader) {
|
||||
// Course administration and Front page administration will have subnodes under "More...".
|
||||
// Front page administration will have subnodes under "More...".
|
||||
$linkname = behat_context_helper::escape(get_string('morenavigationlinks'));
|
||||
$link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]');
|
||||
$link = $this->getSession()->getPage()->find('xpath',
|
||||
$menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]'
|
||||
);
|
||||
// Course administration will have subnodes under "Course administration".
|
||||
$courselinkname = behat_context_helper::escape(get_string('courseadministration'));
|
||||
$courselink = $this->getSession()->getPage()->find('xpath',
|
||||
$menuxpath . '//a[contains(normalize-space(.), ' . $courselinkname . ')]'
|
||||
);
|
||||
if ($link) {
|
||||
$this->execute('behat_general::i_click_on', [$link, 'NodeElement']);
|
||||
$this->select_on_administration_page($nodelist);
|
||||
return;
|
||||
} else if ($courselink) {
|
||||
$this->execute('behat_general::i_click_on', [$courselink, 'NodeElement']);
|
||||
$this->select_on_administration_page($nodelist);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1115,6 +1182,7 @@ class behat_navigation extends behat_base {
|
|||
* First checks to see if we are on this page via the breadcrumb. If not we then attempt to follow the link name given.
|
||||
*
|
||||
* @param string $pagename Name of the breadcrumb item to check and follow.
|
||||
* @Given /^I follow the breadcrumb "(?P<url_string>(?:[^"]|\\")*)"$/
|
||||
*/
|
||||
public function go_to_breadcrumb_location(string $pagename): void {
|
||||
$link = $this->getSession()->getPage()->find(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue