{"version":3,"sources":["a11y-disclosure-nav.js"],"names":["DisclosureNav","domNode","_this","this","_classCallCheck","rootNode","controlledNodes","openIndex","useArrowKeys","topLevelNodes","_toConsumableArray","querySelectorAll","forEach","node","tagName","toLowerCase","hasAttribute","parentNode","querySelector","push","menu","onMenuKeyDown","bind","addEventListener","onButtonClick","onButtonKeyDown","onLinkKeyDown","onBlur","keyboardEvent","nodeList","currentIndex","preventDefault","Math","max","focus","min","length","prevIndex","toggleExpand","contains","event","relatedTarget","button","target","buttonIndex","indexOf","buttonExpanded","targetButtonIndex","document","activeElement","menuContainsFocus","controlFocusByKey","targetLinkIndex","menuLinks","prototype","call","key","index","expanded","toggleMenu","show","style","display","window","menus","disclosureMenus","i","getElementById","arrowKeySwitch","checked"],"mappings":"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","file":"a11y-disclosure-nav.js","sourcesContent":["/*\n * This software or document includes material copied from or derived from Example Disclosure Navigation Menu https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/.\n * Copyright © 2023 World Wide Web Consortium.\n * https://www.w3.org/Consortium/Legal/2023/doc-license\n */\n\n/* eslint class-methods-use-this: \"off\" */\n/* eslint prefer-reflect: \"off\" */\n\n'use strict';\n\nclass DisclosureNav {\n constructor(domNode) {\n this.rootNode = domNode;\n this.controlledNodes = [];\n this.openIndex = null;\n this.useArrowKeys = true;\n this.topLevelNodes = [\n ...this.rootNode.querySelectorAll(\n 'button[aria-controls]'\n )\n ];\n\n this.topLevelNodes.forEach((node) => {\n // handle button + menu\n if (\n node.tagName.toLowerCase() === 'button' &&\n node.hasAttribute('aria-controls')\n ) {\n const menu = node.parentNode.querySelector('ul');\n\n if (menu) {\n // save ref controlled menu\n this.controlledNodes.push(menu);\n\n // collapse menus\n node.setAttribute('aria-expanded', 'false');\n this.toggleMenu(menu, false);\n\n // attach event listeners\n menu.addEventListener('keydown', this.onMenuKeyDown.bind(this));\n node.addEventListener('click', this.onButtonClick.bind(this));\n node.addEventListener('keydown', this.onButtonKeyDown.bind(this));\n }\n } else {\n // handle links\n this.controlledNodes.push(null);\n node.addEventListener('keydown', this.onLinkKeyDown.bind(this));\n }\n });\n\n this.rootNode.addEventListener('focusout', this.onBlur.bind(this));\n }\n\n controlFocusByKey(keyboardEvent, nodeList, currentIndex) {\n switch (keyboardEvent.key) {\n case 'ArrowUp':\n case 'ArrowLeft':\n keyboardEvent.preventDefault();\n if (currentIndex > -1) {\n const prevIndex = Math.max(0, currentIndex - 1);\n\n nodeList[prevIndex].focus();\n }\n break;\n case 'ArrowDown':\n case 'ArrowRight':\n keyboardEvent.preventDefault();\n if (currentIndex > -1) {\n const nextIndex = Math.min(nodeList.length - 1, currentIndex + 1);\n\n nodeList[nextIndex].focus();\n }\n break;\n case 'Home':\n keyboardEvent.preventDefault();\n nodeList[0].focus();\n break;\n case 'End':\n keyboardEvent.preventDefault();\n nodeList[nodeList.length - 1].focus();\n break;\n }\n }\n\n // public function to close open menu\n close() {\n this.toggleExpand(this.openIndex, false);\n }\n\n onBlur(event) {\n const menuContainsFocus = this.rootNode.contains(event.relatedTarget);\n\n if (!menuContainsFocus && this.openIndex !== null) {\n this.toggleExpand(this.openIndex, false);\n }\n }\n\n onButtonClick(event) {\n const button = event.target;\n const buttonIndex = this.topLevelNodes.indexOf(button);\n const buttonExpanded = button.getAttribute('aria-expanded') === 'true';\n\n this.toggleExpand(buttonIndex, !buttonExpanded);\n }\n\n onButtonKeyDown(event) {\n const targetButtonIndex = this.topLevelNodes.indexOf(document.activeElement);\n\n // close on escape\n if (event.key === 'Escape') {\n this.toggleExpand(this.openIndex, false);\n } else if (\n this.useArrowKeys &&\n this.openIndex === targetButtonIndex &&\n event.key === 'ArrowDown'\n ) {\n // move focus into the open menu if the current menu is open\n event.preventDefault();\n this.controlledNodes[this.openIndex].querySelector('a').focus();\n } else if (this.useArrowKeys) {\n // handle arrow key navigation between top-level buttons, if set\n this.controlFocusByKey(event, this.topLevelNodes, targetButtonIndex);\n }\n }\n\n onLinkKeyDown(event) {\n const targetLinkIndex = this.topLevelNodes.indexOf(document.activeElement);\n\n // handle arrow key navigation between top-level buttons, if set\n if (this.useArrowKeys) {\n this.controlFocusByKey(event, this.topLevelNodes, targetLinkIndex);\n }\n }\n\n onMenuKeyDown(event) {\n if (this.openIndex === null) {\n return;\n }\n const menuLinks = Array.prototype.slice.call(\n this.controlledNodes[this.openIndex].querySelectorAll('a')\n );\n const currentIndex = menuLinks.indexOf(document.activeElement);\n\n // close on escape\n if (event.key === 'Escape') {\n this.topLevelNodes[this.openIndex].focus();\n this.toggleExpand(this.openIndex, false);\n } else if (this.useArrowKeys) {\n // handle arrow key navigation within menu links, if set\n this.controlFocusByKey(event, menuLinks, currentIndex);\n }\n }\n\n toggleExpand(index, expanded) {\n // close open menu, if applicable\n if (this.openIndex !== index) {\n this.toggleExpand(this.openIndex, false);\n }\n\n // handle menu at called index\n if (this.topLevelNodes[index]) {\n if (expanded) {\n this.openIndex = index;\n } else {\n this.openIndex = null;\n }\n this.topLevelNodes[index].setAttribute('aria-expanded', expanded);\n this.toggleMenu(this.controlledNodes[index], expanded);\n }\n }\n\n toggleMenu(domNode, show) {\n if (domNode) {\n if (show) {\n domNode.style.display = 'block';\n } else {\n domNode.style.display = 'none';\n }\n }\n }\n\n updateKeyControls(useArrowKeys) {\n this.useArrowKeys = useArrowKeys;\n }\n}\n\n// Initialize Disclosure Menus\nwindow.addEventListener(\n 'load',\n function () {\n const menus = document.querySelectorAll('.js-disclosure-nav');\n const disclosureMenus = [];\n\n for (let i = 0; i < menus.length; i++) {\n disclosureMenus[i] = new DisclosureNav(menus[i]);\n }\n\n // listen to arrow key checkbox\n const arrowKeySwitch = document.getElementById('arrow-behavior-switch');\n\n if (arrowKeySwitch) {\n arrowKeySwitch.addEventListener('change', function () {\n const checked = arrowKeySwitch.checked;\n\n for (let i = 0; i < disclosureMenus.length; i++) {\n disclosureMenus[i].updateKeyControls(checked);\n }\n });\n }\n },\n false\n);\n"]}