diff --git a/admin/search.php b/admin/search.php index 7057575b950..319aa8f7fa5 100644 --- a/admin/search.php +++ b/admin/search.php @@ -91,7 +91,7 @@ if ($hassiteconfig) { if ($showsettingslinks) { $node = $PAGE->settingsnav->find('root', navigation_node::TYPE_SITE_ADMIN); if ($node) { - $secondarynavigation = $OUTPUT->more_menu($PAGE->secondarynav, 'nav-tabs'); + $secondarynavigation = $OUTPUT->more_menu($PAGE->secondarynav, 'nav-tabs', true); echo $OUTPUT->render_from_template('core/settings_link_page', ['node' => $node, 'secondarynavigation' => $secondarynavigation]); } diff --git a/lib/amd/build/moremenu.min.js b/lib/amd/build/moremenu.min.js index 7a0fbf83cb3..c6fafcee184 100644 --- a/lib/amd/build/moremenu.min.js +++ b/lib/amd/build/moremenu.min.js @@ -1,2 +1,2 @@ -define ("core/moremenu",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c={regions:{moredropdown:"[data-region=\"moredropdown\"]",morebutton:"[data-region=\"morebutton\"]"},classes:{dropdownitem:"dropdown-item",dropdownmoremenu:"dropdownmoremenu",dropdowntoggle:"dropdown-toggle",hidden:"d-none",active:"active",nav:"nav",navlink:"nav-link",observed:"observed"},attributes:{menu:"[role=\"menu\"]"}},d=function(a){var b=a.parentNode.offsetHeight+1,g=a.querySelector(c.regions.moredropdown),h=a.querySelector(c.regions.morebutton);if(a.offsetHeight>b){h.classList.remove(c.classes.hidden);var i=Array.from(a.children).reverse();i.forEach(function(d){if(!d.classList.contains(c.classes.dropdownmoremenu)){if(a.offsetHeight>b){var f=a.removeChild(d);e(a,f,!0)}}})}else{if("children"in g){var j=Array.from(g.children);j.forEach(function(c){if(a.offsetHeightb){d(a)}}a.parentNode.classList.add(c.classes.observed)},e=function(a,b){var d=2b){h.classList.remove(c.classes.hidden);var i=Array.from(a.children).reverse();i.forEach(function(d){if(!d.classList.contains(c.classes.dropdownmoremenu)){if(a.offsetHeight>b){var f=a.removeChild(d);e(a,f,!0)}}})}else{if("children"in g){var j=Array.from(g.children);j.forEach(function(c){if(a.offsetHeightb){d(a)}}a.parentNode.classList.add(c.classes.observed)},e=function(a,b){var d=2.\n\n/**\n * Moves wrapping navigation items into a more menu.\n *\n * @module core/moremenu\n * @package core\n * @copyright 2021 Moodle\n * @author Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n/**\n * Moremenu selectors.\n */\nconst Selectors = {\n regions: {\n moredropdown: '[data-region=\"moredropdown\"]',\n morebutton: '[data-region=\"morebutton\"]'\n },\n classes: {\n dropdownitem: 'dropdown-item',\n dropdownmoremenu: 'dropdownmoremenu',\n dropdowntoggle: 'dropdown-toggle',\n hidden: 'd-none',\n active: 'active',\n nav: 'nav',\n navlink: 'nav-link',\n observed: 'observed',\n },\n attributes: {\n menu: '[role=\"menu\"]'\n }\n};\n\n/**\n * Auto Collapse navigation items that wrap into a dropdown menu.\n *\n * @param {HTMLElement} menu The navbar container.\n */\nconst autoCollapse = menu => {\n\n const maxHeight = menu.parentNode.offsetHeight + 1;\n\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n\n // If the menu items wrap and the menu height is larger than the height of the\n // parent then start pushing navlinks into the moreDropdown.\n if (menu.offsetHeight > maxHeight) {\n\n moreButton.classList.remove(Selectors.classes.hidden);\n\n const menuNodes = Array.from(menu.children).reverse();\n menuNodes.forEach(item => {\n if (!item.classList.contains(Selectors.classes.dropdownmoremenu)) {\n // After moving the menu items into the moreDropdown check again\n // if the menu height is still larger then the height of the parent.\n if (menu.offsetHeight > maxHeight) {\n const lastNode = menu.removeChild(item);\n // Move this node into the more dropdown menu.\n moveIntoMoreDropdown(menu, lastNode, true);\n }\n }\n });\n } else {\n // If the menu height is smaller than the height of the parent, then try returning navlinks to the menu.\n\n if ('children' in moreDropdown) {\n const menuNodes = Array.from(moreDropdown.children);\n menuNodes.forEach(item => {\n // Don't move the node to the more menu if it is explicitly defined that\n // this node should be displayed in the more dropdown menu at all times.\n if (menu.offsetHeight < maxHeight && item.dataset.forceintomoremenu !== 'true') {\n const lastNode = moreDropdown.removeChild(item);\n // Move this node from the more dropdown menu into the main section of the menu.\n moveOutOfMoreDropdown(menu, lastNode);\n }\n });\n\n // If there are no more menuNodes in the dropdown we can hide the moreButton.\n if (menuNodes.length === 0) {\n moreButton.classList.add(Selectors.classes.hidden);\n }\n }\n\n if (menu.offsetHeight > maxHeight) {\n autoCollapse(menu);\n }\n }\n menu.parentNode.classList.add(Selectors.classes.observed);\n};\n\n/**\n * Move a node into the \"more\" dropdown menu.\n *\n * This method forces a given navigation node to be added and displayed within the \"more\" dropdown menu.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n * @param {HTMLElement} navNode The navigation node.\n * @param {boolean} prepend Whether to prepend or append the node to the content in the more dropdown menu.\n */\nconst moveIntoMoreDropdown = (menu, navNode, prepend = false) => {\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle);\n\n const navLink = navNode.querySelector('.' + Selectors.classes.navlink);\n if (navLink && !navLink.hasAttribute('role')) {\n // Adding the menuitem role so the dropdown includes the\n // accessibility improvements from theme/boost/amd/src/aria.js\n navLink.setAttribute('role', 'menuitem');\n }\n\n // If there are navLinks that contain an active link in the moreDropdown\n // make the dropdownToggle in the moreButton active.\n if (navLink.classList.contains(Selectors.classes.active)) {\n dropdownToggle.classList.add(Selectors.classes.active);\n }\n\n // Change the styling of the navLink to a dropdownitem and push it into\n // the moreDropdown.\n navLink.classList.remove(Selectors.classes.navlink);\n navLink.classList.add(Selectors.classes.dropdownitem);\n if (prepend) {\n moreDropdown.prepend(navNode);\n } else {\n moreDropdown.append(navNode);\n }\n};\n\n/**\n * Move a node out of the \"more\" dropdown menu.\n *\n * This method forces a given node from the \"more\" dropdown menu to be displayed in the main section of the menu.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n * @param {HTMLElement} navNode The navigation node.\n */\nconst moveOutOfMoreDropdown = (menu, navNode) => {\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle);\n const navLink = navNode.querySelector('.' + Selectors.classes.dropdownitem);\n\n if (navLink) {\n const currentAttribute = navLink.getAttribute('role');\n if (currentAttribute === 'menuitem') {\n navLink.removeAttribute('role');\n }\n }\n\n // Stop displaying the active state on the dropdownToggle if\n // the active navlink is removed.\n if (navLink.classList.contains(Selectors.classes.active)) {\n dropdownToggle.classList.remove(Selectors.classes.active);\n }\n navLink.classList.remove(Selectors.classes.dropdownitem);\n navLink.classList.add(Selectors.classes.navlink);\n menu.insertBefore(navNode, moreButton);\n};\n\n/**\n * Initialise the more menus.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n */\nexport default menu => {\n // Pre-populate the \"more\" dropdown menu with navigation nodes which are set to be displayed in this menu\n // by default at all times.\n if ('children' in menu) {\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n const menuNodes = Array.from(menu.children);\n menuNodes.forEach((item) => {\n if (!item.classList.contains(Selectors.classes.dropdownmoremenu) &&\n item.dataset.forceintomoremenu === 'true') {\n // Append this node into the more dropdown menu.\n moveIntoMoreDropdown(menu, item, false);\n // After adding the node into the more dropdown menu, make sure that the more dropdown menu button\n // is displayed.\n if (moreButton.classList.contains(Selectors.classes.hidden)) {\n moreButton.classList.remove(Selectors.classes.hidden);\n }\n }\n });\n }\n // Populate the more dropdown menu with additional nodes if necessary, depending on the current screen size.\n autoCollapse(menu);\n\n // When the screen size changes make sure the menu still fits.\n window.addEventListener('resize', () => {\n autoCollapse(menu);\n });\n\n const toggledropdown = e => {\n const innerMenu = e.target.parentNode.querySelector(Selectors.attributes.menu);\n if (innerMenu) {\n innerMenu.classList.toggle('show');\n }\n e.stopPropagation();\n };\n\n // If there are dropdowns in the MoreMenu, add a new\n // event listener to show the contents on click and prevent the\n // moreMenu from closing.\n $('.' + Selectors.classes.dropdownmoremenu).on('show.bs.dropdown', function() {\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n moreDropdown.querySelectorAll('.dropdown').forEach((dropdown) => {\n dropdown.removeEventListener('click', toggledropdown, true);\n dropdown.addEventListener('click', toggledropdown, true);\n });\n });\n};\n"],"file":"moremenu.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/moremenu.js"],"names":["Selectors","regions","moredropdown","morebutton","classes","dropdownitem","dropdownmoremenu","dropdowntoggle","hidden","active","nav","navlink","observed","attributes","menu","autoCollapse","maxHeight","parentNode","offsetHeight","moreDropdown","querySelector","moreButton","classList","remove","menuNodes","Array","from","children","reverse","forEach","item","contains","lastNode","removeChild","moveIntoMoreDropdown","dataset","forceintomoremenu","moveOutOfMoreDropdown","length","add","navNode","prepend","dropdownToggle","navLink","setAttribute","getAttribute","append","currentAttribute","removeAttribute","insertBefore","window","addEventListener","toggledropdown","e","innerMenu","target","toggle","stopPropagation","on","querySelectorAll","dropdown","removeEventListener"],"mappings":"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","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 .\n\n/**\n * Moves wrapping navigation items into a more menu.\n *\n * @module core/moremenu\n * @package core\n * @copyright 2021 Moodle\n * @author Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n/**\n * Moremenu selectors.\n */\nconst Selectors = {\n regions: {\n moredropdown: '[data-region=\"moredropdown\"]',\n morebutton: '[data-region=\"morebutton\"]'\n },\n classes: {\n dropdownitem: 'dropdown-item',\n dropdownmoremenu: 'dropdownmoremenu',\n dropdowntoggle: 'dropdown-toggle',\n hidden: 'd-none',\n active: 'active',\n nav: 'nav',\n navlink: 'nav-link',\n observed: 'observed',\n },\n attributes: {\n menu: '[role=\"menu\"]'\n }\n};\n\n/**\n * Auto Collapse navigation items that wrap into a dropdown menu.\n *\n * @param {HTMLElement} menu The navbar container.\n */\nconst autoCollapse = menu => {\n\n const maxHeight = menu.parentNode.offsetHeight + 1;\n\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n\n // If the menu items wrap and the menu height is larger than the height of the\n // parent then start pushing navlinks into the moreDropdown.\n if (menu.offsetHeight > maxHeight) {\n\n moreButton.classList.remove(Selectors.classes.hidden);\n\n const menuNodes = Array.from(menu.children).reverse();\n menuNodes.forEach(item => {\n if (!item.classList.contains(Selectors.classes.dropdownmoremenu)) {\n // After moving the menu items into the moreDropdown check again\n // if the menu height is still larger then the height of the parent.\n if (menu.offsetHeight > maxHeight) {\n const lastNode = menu.removeChild(item);\n // Move this node into the more dropdown menu.\n moveIntoMoreDropdown(menu, lastNode, true);\n }\n }\n });\n } else {\n // If the menu height is smaller than the height of the parent, then try returning navlinks to the menu.\n\n if ('children' in moreDropdown) {\n const menuNodes = Array.from(moreDropdown.children);\n menuNodes.forEach(item => {\n // Don't move the node to the more menu if it is explicitly defined that\n // this node should be displayed in the more dropdown menu at all times.\n if (menu.offsetHeight < maxHeight && item.dataset.forceintomoremenu !== 'true') {\n const lastNode = moreDropdown.removeChild(item);\n // Move this node from the more dropdown menu into the main section of the menu.\n moveOutOfMoreDropdown(menu, lastNode);\n }\n });\n\n // If there are no more menuNodes in the dropdown we can hide the moreButton.\n if (menuNodes.length === 0) {\n moreButton.classList.add(Selectors.classes.hidden);\n }\n }\n\n if (menu.offsetHeight > maxHeight) {\n autoCollapse(menu);\n }\n }\n menu.parentNode.classList.add(Selectors.classes.observed);\n};\n\n/**\n * Move a node into the \"more\" dropdown menu.\n *\n * This method forces a given navigation node to be added and displayed within the \"more\" dropdown menu.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n * @param {HTMLElement} navNode The navigation node.\n * @param {boolean} prepend Whether to prepend or append the node to the content in the more dropdown menu.\n */\nconst moveIntoMoreDropdown = (menu, navNode, prepend = false) => {\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle);\n\n const navLink = navNode.querySelector('.' + Selectors.classes.navlink);\n navNode.setAttribute('prev-role', navNode.getAttribute('role'));\n navNode.setAttribute('role', 'menuitem');\n\n // If there are navLinks that contain an active link in the moreDropdown\n // make the dropdownToggle in the moreButton active.\n if (navLink.classList.contains(Selectors.classes.active)) {\n dropdownToggle.classList.add(Selectors.classes.active);\n }\n\n // Change the styling of the navLink to a dropdownitem and push it into\n // the moreDropdown.\n navLink.classList.remove(Selectors.classes.navlink);\n navLink.classList.add(Selectors.classes.dropdownitem);\n if (prepend) {\n moreDropdown.prepend(navNode);\n } else {\n moreDropdown.append(navNode);\n }\n};\n\n/**\n * Move a node out of the \"more\" dropdown menu.\n *\n * This method forces a given node from the \"more\" dropdown menu to be displayed in the main section of the menu.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n * @param {HTMLElement} navNode The navigation node.\n */\nconst moveOutOfMoreDropdown = (menu, navNode) => {\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle);\n const navLink = navNode.querySelector('.' + Selectors.classes.dropdownitem);\n\n navNode.setAttribute('role', navNode.getAttribute('prev-role'));\n if (navLink) {\n const currentAttribute = navLink.getAttribute('role');\n if (currentAttribute === 'menuitem') {\n navLink.removeAttribute('role');\n }\n }\n\n // Stop displaying the active state on the dropdownToggle if\n // the active navlink is removed.\n if (navLink.classList.contains(Selectors.classes.active)) {\n dropdownToggle.classList.remove(Selectors.classes.active);\n }\n navLink.classList.remove(Selectors.classes.dropdownitem);\n navLink.classList.add(Selectors.classes.navlink);\n menu.insertBefore(navNode, moreButton);\n};\n\n/**\n * Initialise the more menus.\n *\n * @param {HTMLElement} menu The navbar moremenu.\n */\nexport default menu => {\n // Pre-populate the \"more\" dropdown menu with navigation nodes which are set to be displayed in this menu\n // by default at all times.\n if ('children' in menu) {\n const moreButton = menu.querySelector(Selectors.regions.morebutton);\n const menuNodes = Array.from(menu.children);\n menuNodes.forEach((item) => {\n if (!item.classList.contains(Selectors.classes.dropdownmoremenu) &&\n item.dataset.forceintomoremenu === 'true') {\n // Append this node into the more dropdown menu.\n moveIntoMoreDropdown(menu, item, false);\n // After adding the node into the more dropdown menu, make sure that the more dropdown menu button\n // is displayed.\n if (moreButton.classList.contains(Selectors.classes.hidden)) {\n moreButton.classList.remove(Selectors.classes.hidden);\n }\n }\n });\n }\n // Populate the more dropdown menu with additional nodes if necessary, depending on the current screen size.\n autoCollapse(menu);\n\n // When the screen size changes make sure the menu still fits.\n window.addEventListener('resize', () => {\n autoCollapse(menu);\n });\n\n const toggledropdown = e => {\n const innerMenu = e.target.parentNode.querySelector(Selectors.attributes.menu);\n if (innerMenu) {\n innerMenu.classList.toggle('show');\n }\n e.stopPropagation();\n };\n\n // If there are dropdowns in the MoreMenu, add a new\n // event listener to show the contents on click and prevent the\n // moreMenu from closing.\n $('.' + Selectors.classes.dropdownmoremenu).on('show.bs.dropdown', function() {\n const moreDropdown = menu.querySelector(Selectors.regions.moredropdown);\n moreDropdown.querySelectorAll('.dropdown').forEach((dropdown) => {\n dropdown.removeEventListener('click', toggledropdown, true);\n dropdown.addEventListener('click', toggledropdown, true);\n });\n });\n};\n"],"file":"moremenu.min.js"} \ No newline at end of file diff --git a/lib/amd/src/moremenu.js b/lib/amd/src/moremenu.js index 804edfa78ba..e61fad49091 100644 --- a/lib/amd/src/moremenu.js +++ b/lib/amd/src/moremenu.js @@ -119,11 +119,8 @@ const moveIntoMoreDropdown = (menu, navNode, prepend = false) => { const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle); const navLink = navNode.querySelector('.' + Selectors.classes.navlink); - if (navLink && !navLink.hasAttribute('role')) { - // Adding the menuitem role so the dropdown includes the - // accessibility improvements from theme/boost/amd/src/aria.js - navLink.setAttribute('role', 'menuitem'); - } + navNode.setAttribute('prev-role', navNode.getAttribute('role')); + navNode.setAttribute('role', 'menuitem'); // If there are navLinks that contain an active link in the moreDropdown // make the dropdownToggle in the moreButton active. @@ -155,6 +152,7 @@ const moveOutOfMoreDropdown = (menu, navNode) => { const dropdownToggle = menu.querySelector('.' + Selectors.classes.dropdowntoggle); const navLink = navNode.querySelector('.' + Selectors.classes.dropdownitem); + navNode.setAttribute('role', navNode.getAttribute('prev-role')); if (navLink) { const currentAttribute = navLink.getAttribute('role'); if (currentAttribute === 'menuitem') { diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 42007a1aad0..3f1e959c06a 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -3813,9 +3813,10 @@ EOD; * * @param array $content * @param string $navbarstyle navbar-nav or nav-tabs + * @param boolean $hastabs * @return string */ - public function more_menu($content, $navbarstyle) { + public function more_menu($content, $navbarstyle, $hastabs = false) { $tabs = ($navbarstyle == 'nav-tabs'); if (is_object($content)) { if (!isset($content->children) || count($content->children) == 0) { @@ -3824,13 +3825,13 @@ EOD; return $this->render_from_template('core/moremenu', (object) [ 'nodecollection' => $content, 'navbarstyle' => $navbarstyle, - 'tabs' => $tabs + 'tabs' => $hastabs ]); } else { return $this->render_from_template('core/moremenu', (object) [ 'nodearray' => $content, 'navbarstyle' => $navbarstyle, - 'tabs' => $tabs + 'tabs' => $hastabs ]); } } diff --git a/lib/templates/moremenu.mustache b/lib/templates/moremenu.mustache index 2197c4bb116..325049ae727 100644 --- a/lib/templates/moremenu.mustache +++ b/lib/templates/moremenu.mustache @@ -45,7 +45,7 @@ } }}