{"version":3,"file":"aria.min.js","sources":["https:\/\/uciliste.zastitanaradu.hr\/theme\/boost\/amd\/src\/aria.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 .\n\n\/**\n * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost\/aria\n * @copyright 2018 Damyon Wiese \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n *\/\n\nimport $ from 'jquery';\nimport Pending from 'core\/pending';\n\n\/**\n * Drop downs from bootstrap don't support keyboard accessibility by default.\n *\/\nconst dropdownFix = () => {\n let focusEnd = false;\n const setFocusEnd = (end = true) => {\n focusEnd = end;\n };\n const getFocusEnd = () => {\n const result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n \/\/ Special handling for navigation keys when menu is open.\n const shiftFocus = element => {\n const delayedFocus = pendingPromise => {\n element.focus();\n pendingPromise.resolve();\n };\n setTimeout(delayedFocus, 50, new Pending('core\/aria:delayed-focus'));\n };\n\n \/\/ Event handling for the dropdown menu button.\n const handleMenuButton = e => {\n const trigger = e.key;\n let fixFocus = false;\n\n \/\/ Space key or Enter key opens the menu.\n if (trigger === ' ' || trigger === 'Enter') {\n fixFocus = true;\n \/\/ Cancel random scroll.\n e.preventDefault();\n \/\/ Open the menu instead.\n e.target.click();\n }\n\n \/\/ Up and Down keys also open the menu.\n if (trigger === 'ArrowUp' || trigger === 'ArrowDown') {\n fixFocus = true;\n }\n\n if (!fixFocus) {\n \/\/ No need to fix the focus. Return early.\n return;\n }\n\n \/\/ Fix the focus on the menu items when the menu is opened.\n const menu = e.target.parentElement.querySelector('[role=\"menu\"]');\n let menuItems = false;\n let foundMenuItem = false;\n\n if (menu) {\n menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n \/\/ Up key opens the menu at the end.\n if (trigger === 'ArrowUp') {\n setFocusEnd();\n } else {\n setFocusEnd(false);\n }\n\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n \/\/ The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n };\n\n \/\/ Search for menu items by finding the first item that has\n \/\/ text starting with the typed character (case insensitive).\n document.addEventListener('keypress', e => {\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const menu = e.target.closest('[role=\"menu\"]');\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n const trigger = e.key.toLowerCase();\n\n for (let i = 0; i < menuItems.length; i++) {\n const item = menuItems[i];\n const itemText = item.text.trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n }\n });\n\n \/\/ Keyboard navigation for arrow keys, home and end keys.\n document.addEventListener('keydown', e => {\n\n \/\/ We only want to set focus when users access the dropdown via keyboard as per\n \/\/ guidelines defined in w3 aria practices 1.1 menu-button.\n if (e.target.matches('[data-toggle=\"dropdown\"]')) {\n handleMenuButton(e);\n }\n\n if (e.target.matches('.dropdown [role=\"menu\"] [role=\"menuitem\"]')) {\n const trigger = e.key;\n let next = false;\n const menu = e.target.closest('[role=\"menu\"]');\n\n if (!menu) {\n return;\n }\n const menuItems = menu.querySelectorAll('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n \/\/ Down key.\n if (trigger == 'ArrowDown') {\n for (let i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n \/\/ Wrap to first item.\n next = menuItems[0];\n }\n } else if (trigger == 'ArrowUp') {\n \/\/ Up key.\n for (let i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n \/\/ Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n } else if (trigger == 'Home') {\n \/\/ Home key.\n next = menuItems[0];\n\n } else if (trigger == 'End') {\n \/\/ End key.\n next = menuItems[menuItems.length - 1];\n }\n\n \/\/ Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n }\n });\n\n $('.dropdown').on('hidden.bs.dropdown', e => {\n \/\/ We need to focus on the menu trigger.\n const trigger = e.target.querySelector('[data-toggle=\"dropdown\"]');\n const focused = document.activeElement != document.body ? document.activeElement : null;\n if (trigger && focused && e.target.contains(focused)) {\n shiftFocus(trigger);\n }\n });\n};\n\n\/**\n * After page load, focus on any element with special autofocus attribute.\n *\/\nconst autoFocus = () => {\n window.addEventListener(\"load\", () => {\n const alerts = document.querySelectorAll('[data-aria-autofocus=\"true\"][role=\"alert\"]');\n Array.prototype.forEach.call(alerts, autofocusElement => {\n \/\/ According to the specification an role=\"alert\" region is only read out on change to the content\n \/\/ of that region.\n autofocusElement.innerHTML += ' ';\n autofocusElement.removeAttribute('data-aria-autofocus');\n });\n });\n};\n\n\/**\n * Changes the focus to the correct tab based on the key that is pressed.\n * @param {KeyboardEvent} e\n *\/\nconst updateTabFocus = e => {\n const tabList = e.target.closest('[role=\"tablist\"]');\n const vertical = tabList.getAttribute('aria-orientation') == 'vertical';\n const rtl = window.right_to_left();\n const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');\n const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');\n const tabs = Array.prototype.filter.call(\n tabList.querySelectorAll('[role=\"tab\"]'),\n tab => getComputedStyle(tab).display !== 'none'); \/\/ We only work with the visible tabs.\n\n for (let i = 0; i < tabs.length; i++) {\n tabs[i].index = i;\n }\n\n switch (e.key) {\n case arrowNext:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index + 1]) {\n tabs[e.target.index + 1].focus();\n } else {\n tabs[0].focus();\n }\n break;\n case arrowPrevious:\n e.preventDefault();\n if (e.target.index !== undefined && tabs[e.target.index - 1]) {\n tabs[e.target.index - 1].focus();\n } else {\n tabs[tabs.length - 1].focus();\n }\n break;\n case 'Home':\n e.preventDefault();\n tabs[0].focus();\n break;\n case 'End':\n e.preventDefault();\n tabs[tabs.length - 1].focus();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n};\n\n\/**\n * Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.\n *\/\nconst tabElementFix = () => {\n document.addEventListener('keydown', e => {\n if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(e.key)) {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n updateTabFocus(e);\n }\n }\n });\n\n document.addEventListener('click', e => {\n if (e.target.matches('[role=\"tablist\"] [role=\"tab\"]')) {\n const tabs = e.target.closest('[role=\"tablist\"]').querySelectorAll('[role=\"tab\"]');\n e.preventDefault();\n $(e.target).tab('show');\n tabs.forEach(tab => {\n tab.tabIndex = -1;\n });\n e.target.tabIndex = 0;\n }\n });\n};\n\nexport const init = () => {\n dropdownFix();\n autoFocus();\n tabElementFix();\n};\n"],"names":["dropdownFix","focusEnd","setFocusEnd","end","shiftFocus","element","setTimeout","pendingPromise","focus","resolve","Pending","handleMenuButton","e","trigger","key","fixFocus","preventDefault","target","click","result","menu","parentElement","querySelector","menuItems","foundMenuItem","querySelectorAll","length","document","addEventListener","matches","closest","toLowerCase","i","item","text","trim","indexOf","next","on","focused","activeElement","body","contains","tabElementFix","includes","tabList","vertical","getAttribute","rtl","window","right_to_left","arrowNext","arrowPrevious","tabs","Array","prototype","filter","call","tab","getComputedStyle","display","index","undefined","forEach","tabIndex","updateTabFocus","alerts","autofocusElement","innerHTML","removeAttribute"],"mappings":"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"}