/* eslint-env browser */ import { copyToClipboard, isElementWithClassNameInEventPath } from './helpers'; const findNav = (element: HTMLElement): HTMLElement => { const parent = element.parentElement; if (parent) { if (parent.classList.contains('nav')) { return parent; } return findNav(parent); } return element; }; // eslint-disable-next-line max-len const closeResponsiveNav = (navElements: NodeListOf, keepOpen: HTMLElement | null = null): void => { const navToggledClass = 'nav--toggled'; navElements.forEach((n) => { const button = n.querySelector('.nav__toggle') as HTMLElement; if (n !== keepOpen) { if (n.classList.contains(navToggledClass)) { button.focus(); button.setAttribute('aria-expanded', 'false'); } n.classList.remove(navToggledClass); } }); }; const setResponsiveToggle = (navElements: NodeListOf): CleanUpPair[] => { const toggleMenu = (button: HTMLElement) => { const parent = findNav(button); // const hideItems: NodeListOf = parent.querySelectorAll('.nav__item'); // // Only shows overflown elements when the menu is extended // hideItems.forEach(item => { // const currentDisplay = window.getComputedStyle(item).display; // if (!item.classList.contains('nav__item--is-overflown')) { // item.style.display = currentDisplay === 'none' ? 'inline-flex' : 'none'; // } // }); // // All elements get display: inline-flex when there is clicked outside of the button // const handleDocumentClick = (event: MouseEvent) => { // if (!parent.contains(event.target as Node)) { // hideItems.forEach(item => { // item.style.display = 'inline-flex'; // }); // } // }; // document.body.addEventListener('click', handleDocumentClick); const navItems = parent.querySelector('.nav__items'); const lastNavItem = navItems?.querySelector('.nav__item:last-of-type'); navItems?.classList.add('nav__items--fadeout'); const firstElement = navItems?.querySelector('.nav__item--is-overflown') as HTMLElement; if (firstElement) { firstElement.focus(); } const transitionListener = () => { parent.classList.toggle('nav--toggled'); navItems?.classList.remove('nav__items--fadeout'); lastNavItem?.removeEventListener('transitionend', transitionListener); }; lastNavItem?.addEventListener('transitionend', transitionListener); return parent; }; const cleanUp: CleanUpPair[] = []; const toggle = document.querySelectorAll('.nav__toggle'); toggle.forEach((button) => { const clickEvent = () => { const nav = toggleMenu(button as HTMLElement); const ariaExpanded = button.getAttribute('aria-expanded'); button.setAttribute('aria-expanded', ariaExpanded === 'false' ? 'true' : 'false'); closeResponsiveNav(navElements, nav); }; cleanUp.push({ element: button, clickEvent, }); button.addEventListener('click', clickEvent); }); return cleanUp; }; const setResponsiveNav = ( navElements: NodeListOf, navElement: Element, ): SetResponsiveNavCleanUp => { const navToggledClass = 'nav--toggled'; const navItemsClass = 'nav__items'; // gitlab #117 navElement.classList.remove(navToggledClass); const navItemsParent = navElement.querySelector(`.${navItemsClass}`); if (navItemsParent) { const navItems = navItemsParent.querySelectorAll('.nav__item'); const isOverflownClass = 'nav__item--is-overflown'; const hasOverflowClass = 'nav--has-overflow'; const isActiveClass = 'nav__item--active'; let hasOverflown = false; for (let i = navItems.length - 1; i >= 0; i -= 1) { const nav = navItems[i] as HTMLElement; const top = nav.offsetTop; if (top > 0) { nav.classList.add(isOverflownClass); navElement.classList.add(hasOverflowClass); hasOverflown = true; } else if (!nav.classList.contains(isActiveClass)) { nav.classList.remove(isOverflownClass); } } if (!hasOverflown) { navElement.classList.remove(hasOverflowClass); const isActive = navElement.querySelector(`.${isActiveClass}`); if (isActive) { isActive.classList.remove(isOverflownClass); } } } // gitlab #115 const bodyClickEvent = (e: Event) => { if (!(e.target as HTMLElement).classList.contains('nav__toggle') && !isElementWithClassNameInEventPath(e as MouseEvent, navItemsClass)) { closeResponsiveNav(navElements); } }; document.querySelector('body')?.addEventListener('click', bodyClickEvent); return { element: document.querySelector('body'), clickEvent: bodyClickEvent, }; }; const closeSubNav = (buttons: NodeListOf, keepOpen: Element | null = null) => { const subNavClass = 'sub-nav--toggled'; buttons.forEach((button) => { if (button !== keepOpen) { if (button?.parentElement?.classList.contains(subNavClass)) { (button as HTMLElement).focus(); button.setAttribute('aria-expanded', 'false'); } button?.parentElement?.classList.remove(subNavClass); } }); }; const setSubNavToggle = (buttons: NodeListOf, button: Element): SetSubNavToggleCleanUp => { const subNavClass = 'sub-nav--toggled'; const buttonClickEvent = () => { button?.parentElement?.classList.toggle(subNavClass); if (button?.parentElement?.classList.contains(subNavClass)) { button.setAttribute('aria-expanded', 'true'); } else { button.setAttribute('aria-expanded', 'false'); } closeSubNav(buttons, button); }; button.addEventListener('click', buttonClickEvent); // gitlab #115 const bodyClickEvent = (e: Event) => { if (!isElementWithClassNameInEventPath(e as MouseEvent, 'sub-nav')) { closeSubNav(buttons); } }; document.querySelector('body')?.addEventListener('click', bodyClickEvent); return { buttonClickEvent, element: document.querySelector('body'), bodyClickEvent, }; }; const setClickMessage = (( text: string, copyElement: Element, clickElement: Element | null, ctcThis: HTMLElement | null, listener: () => void, ): void => { if (ctcThis && clickElement) { // Vi kopierer teksten til clipboard copyToClipboard(ctcThis.innerText).then(() => { copyElement.classList.add('copy-to-clipboard--confirm'); if (copyElement === clickElement) { copyElement.classList.add('copy-to-clipboard--done'); } // Laver en span, der viser, at teksten er kopieret const ctcThisMessage = document.createElement('span'); ctcThisMessage.classList.add('copy-to-clipboard__this__confirm-message'); ctcThisMessage.innerText = text; ctcThis.appendChild(ctcThisMessage); // Efter 1,2 sekunder fjerner vi beskeden igen clickElement.removeEventListener('click', listener); setTimeout(() => { copyElement.classList.remove('copy-to-clipboard--confirm'); ctcThisMessage.remove(); clickElement.addEventListener('click', listener); }, 1200); }); } }); const setCopyToClipboard = (element: HTMLElement, text = 'Kopieret!'): void => { const ctcThis = element.querySelector('.copy-to-clipboard__this'); // Hvis det er en knap, så sætter vi click event på knappen if ((element as HTMLButtonElement).type === 'button') { const listener = (): void => { setClickMessage(text, element, element, ctcThis, listener); }; element.addEventListener('click', listener); // Hvis det ikke er en knap, finder vi knappen "inde i" elementet } else { const btn = element.querySelector('.copy-to-clipboard__execute'); const listener = (): void => { setClickMessage(text, element, btn, ctcThis, listener); }; btn?.addEventListener('click', listener); } }; const setSearchToggle = (navSearch: Element, button: Element): void => { const toggleClass = 'nav__search--toggled'; button.addEventListener('click', () => { if (navSearch.classList.contains(toggleClass)) { button.setAttribute('aria-expanded', 'false'); navSearch.classList.remove(toggleClass); } else { button.setAttribute('aria-expanded', 'true'); navSearch.classList.add(toggleClass); } }); }; export { findNav, setResponsiveToggle, setResponsiveNav, setSubNavToggle, setCopyToClipboard, setSearchToggle, };