1
0
mirror of https://github.com/moodle/moodle.git synced 2025-03-18 06:31:22 +01:00
moodle/lib/amd/build/menu_navigation.min.js.map
Jose 5a010c604d
MDL-82298 navigation: Add setting data-disableactive on moremenu items
This setting will avoid conflicts between checkmark and
bfcache. The removed function added as part of the MDL-77732
is no longer required as the behaviour on the menu items (including the
secondary navigation) is not altered anymore by the menuItemHelper function
(menu_navigation file).
2024-09-25 22:38:19 +08:00

1 line
13 KiB
Plaintext

{"version":3,"file":"menu_navigation.min.js","sources":["../src/menu_navigation.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 * Keyboard initialization for a given html node.\n *\n * @module core/menu_navigation\n * @copyright 2021 Moodle\n * @author Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst SELECTORS = {\n 'menuitem': '[role=\"menuitem\"]',\n 'tab': '[role=\"tab\"]',\n 'dropdowntoggle': '[data-toggle=\"dropdown\"]',\n};\n\nlet openDropdownNode = null;\n\n/**\n * Small helper function to check if a given node is null or not.\n *\n * @param {HTMLElement|null} item The node that we want to compare.\n * @param {HTMLElement} fallback Either the first node or final node that can be focused on.\n * @return {HTMLElement}\n */\nconst clickErrorHandler = (item, fallback) => {\n if (item !== null) {\n return item;\n } else {\n return fallback;\n }\n};\n\n/**\n * Control classes etc of the selected dropdown item and its' parent <a>\n *\n * @param {HTMLElement} src The node within the dropdown the user selected.\n */\nconst menuItemHelper = src => {\n let parent;\n\n // Do not apply any actions if the selected dropdown item is explicitly instructing to not display an active state.\n if (src.dataset.disableactive) {\n return;\n }\n // Handling for dropdown escapes.\n // A bulk of the handling is already done by aria.js just add polish.\n if (src.classList.contains('dropdown-item')) {\n parent = src.closest('.dropdown-menu');\n const dropDownToggle = document.getElementById(parent.getAttribute('aria-labelledby'));\n dropDownToggle.classList.add('active');\n dropDownToggle.setAttribute('tabindex', 0);\n } else if (src.matches(`${SELECTORS.tab},${SELECTORS.menuitem}`) && !src.matches(SELECTORS.dropdowntoggle)) {\n parent = src.parentElement.parentElement.querySelector('.dropdown-menu');\n } else {\n return;\n }\n // Remove active class from any other dropdown elements.\n Array.prototype.forEach.call(parent.children, node => {\n const menuItem = node.querySelector(SELECTORS.menuitem);\n if (menuItem !== null) {\n menuItem.classList.remove('active');\n // Remove aria selection state.\n menuItem.removeAttribute('aria-current');\n }\n });\n // Set the applicable element's selection state.\n if (src.getAttribute('role') === 'menuitem') {\n src.setAttribute('aria-current', 'true');\n }\n};\n\n/**\n * Defined keyboard event handling so we can remove listeners on nodes on resize etc.\n *\n * @param {event} e The triggering element and key presses etc.\n */\nconst keyboardListenerEvents = e => {\n const src = e.srcElement;\n const firstNode = e.currentTarget.firstElementChild;\n const lastNode = findUsableLastNode(e.currentTarget);\n\n // Handling for dropdown escapes.\n // A bulk of the handling is already done by aria.js just add polish.\n if (src.classList.contains('dropdown-item')) {\n if (e.key == 'ArrowRight' ||\n e.key == 'ArrowLeft') {\n e.preventDefault();\n if (openDropdownNode !== null) {\n openDropdownNode.parentElement.click();\n }\n }\n if (e.key == ' ' ||\n e.key == 'Enter') {\n e.preventDefault();\n\n menuItemHelper(src);\n\n if (!src.parentElement.classList.contains('dropdown')) {\n src.click();\n }\n }\n } else {\n const rtl = window.right_to_left();\n const arrowNext = rtl ? 'ArrowLeft' : 'ArrowRight';\n const arrowPrevious = rtl ? 'ArrowRight' : 'ArrowLeft';\n\n if (src.getAttribute('role') === 'menuitem') {\n // When not rendered within a dropdown menu, handle keyboard navigation if the element is rendered as a menu item.\n if (e.key == arrowNext) {\n e.preventDefault();\n setFocusNext(src, firstNode);\n }\n if (e.key == arrowPrevious) {\n e.preventDefault();\n setFocusPrev(src, lastNode);\n }\n // Let aria.js handle the dropdowns.\n if (e.key == 'ArrowUp' ||\n e.key == 'ArrowDown') {\n openDropdownNode = src;\n e.preventDefault();\n }\n if (e.key == 'Home') {\n e.preventDefault();\n setFocusHomeEnd(firstNode);\n }\n if (e.key == 'End') {\n e.preventDefault();\n setFocusHomeEnd(lastNode);\n }\n }\n\n if (e.key == ' ' ||\n e.key == 'Enter') {\n e.preventDefault();\n // Aria.js handles dropdowns etc.\n if (!src.parentElement.classList.contains('dropdown')) {\n src.click();\n }\n }\n }\n};\n\n/**\n * Defined click event handling so we can remove listeners on nodes on resize etc.\n *\n * @param {event} e The triggering element and key presses etc.\n */\nconst clickListenerEvents = e => {\n const src = e.srcElement;\n menuItemHelper(src);\n};\n\n/**\n * The initial entry point that a given module can pass a HTMLElement.\n *\n * @param {HTMLElement} elementRoot The menu to add handlers upon.\n */\nexport default elementRoot => {\n // Remove any and all instances of old listeners on the passed element.\n elementRoot.removeEventListener('keydown', keyboardListenerEvents);\n elementRoot.removeEventListener('click', clickListenerEvents);\n // (Re)apply our event listeners to the passed element.\n elementRoot.addEventListener('keydown', keyboardListenerEvents);\n elementRoot.addEventListener('click', clickListenerEvents);\n};\n\n/**\n * Handle the focusing to the next element in the dropdown.\n *\n * @param {HTMLElement|null} currentNode The node that we want to take action on.\n * @param {HTMLElement} firstNode The backup node to focus as a last resort.\n */\nconst setFocusNext = (currentNode, firstNode) => {\n const listElement = currentNode.parentElement;\n const nextListItem = ((el) => {\n do {\n el = el.nextElementSibling;\n } while (el && !el.offsetHeight); // We only work with the visible tabs.\n return el;\n })(listElement);\n const nodeToSelect = clickErrorHandler(nextListItem, firstNode);\n const parent = listElement.parentElement;\n const isTabList = parent.getAttribute('role') === 'tablist';\n const itemSelector = isTabList ? SELECTORS.tab : SELECTORS.menuitem;\n const menuItem = nodeToSelect.querySelector(itemSelector);\n menuItem.focus();\n};\n\n/**\n * Handle the focusing to the previous element in the dropdown.\n *\n * @param {HTMLElement|null} currentNode The node that we want to take action on.\n * @param {HTMLElement} lastNode The backup node to focus as a last resort.\n */\nconst setFocusPrev = (currentNode, lastNode) => {\n const listElement = currentNode.parentElement;\n const nextListItem = ((el) => {\n do {\n el = el.previousElementSibling;\n } while (el && !el.offsetHeight); // We only work with the visible tabs.\n return el;\n })(listElement);\n const nodeToSelect = clickErrorHandler(nextListItem, lastNode);\n const parent = listElement.parentElement;\n const isTabList = parent.getAttribute('role') === 'tablist';\n const itemSelector = isTabList ? SELECTORS.tab : SELECTORS.menuitem;\n const menuItem = nodeToSelect.querySelector(itemSelector);\n menuItem.focus();\n};\n\n/**\n * Focus on either the start or end of a nav list.\n *\n * @param {HTMLElement} node The element to focus on.\n */\nconst setFocusHomeEnd = node => {\n node.querySelector(SELECTORS.menuitem).focus();\n};\n\n/**\n * We need to look within the menu to find a last node we can add focus to.\n *\n * @param {HTMLElement} elementRoot Menu to find a final child node within.\n * @return {HTMLElement}\n */\nconst findUsableLastNode = elementRoot => {\n const lastNode = elementRoot.lastElementChild;\n\n // An example is the more menu existing but hidden on the page for the time being.\n if (!lastNode.classList.contains('d-none')) {\n return elementRoot.lastElementChild;\n } else {\n // Cast the HTMLCollection & reverse it.\n const extractedNodes = Array.prototype.map.call(elementRoot.children, node => {\n return node;\n }).reverse();\n\n // Get rid of any nodes we can not set focus on.\n const nodesToUse = extractedNodes.filter((node => {\n if (!node.classList.contains('d-none')) {\n return node;\n }\n }));\n\n // If we find no elements we can set focus on, fall back to the absolute first element.\n if (nodesToUse.length !== 0) {\n return nodesToUse[0];\n } else {\n return elementRoot.firstElementChild;\n }\n }\n};\n"],"names":["SELECTORS","openDropdownNode","clickErrorHandler","item","fallback","menuItemHelper","src","parent","dataset","disableactive","classList","contains","closest","dropDownToggle","document","getElementById","getAttribute","add","setAttribute","matches","parentElement","querySelector","Array","prototype","forEach","call","children","node","menuItem","remove","removeAttribute","keyboardListenerEvents","e","srcElement","firstNode","currentTarget","firstElementChild","lastNode","findUsableLastNode","key","preventDefault","click","rtl","window","right_to_left","arrowNext","arrowPrevious","setFocusNext","setFocusPrev","setFocusHomeEnd","clickListenerEvents","elementRoot","removeEventListener","addEventListener","currentNode","listElement","nextListItem","el","nextElementSibling","offsetHeight","nodeToSelect","itemSelector","focus","previousElementSibling","lastElementChild","nodesToUse","map","reverse","filter","length"],"mappings":"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"}