/** * Global scripts */ window.addEventListener('load', (event) => { /** * Vars */ //functional let vh = '100vh' let currentScrollPos = 0 let prevScrollPos = 0 let menuToggledScrollPos let menuIsOpen = false let desktopMenuIsOpen = false let mobileMenuIsOpen = false //media query const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream const isDesktop = window.matchMedia('(min-width: 80rem)') // DOM elements const body = document.body const header = document.querySelector('.site-header') const logo = document.querySelector('.site-logo') const a11y_ariaexpanded = document.querySelectorAll('[aria-expanded="false"]') const menuItems = document.querySelectorAll('#site-header-main-nav > ul > .menu-item-has-children') const menuSubItems = document.querySelectorAll('.site-header-navbar-submenu-0 li .menu-item') const menuBtn = document.getElementById('menu-btn') const overlay = document.getElementById('overlay') const menuMobile = document.getElementById('menu-mobile') const pageWrapper = document.getElementById('site-content-wrapper') const accordionMenuItems = document.querySelectorAll('[data-toggle-menu-items]') const footer = document.getElementById('site-footer') /** * Check if iOS, then set --vh */ if (isIOS && window.matchMedia("(max-width: 1024px)").matches) { document.documentElement.classList.add('is-ios') } function set100vh() { // If window size is iPad or smaller, then use JS to set screen height. if (isIOS && window.matchMedia("(max-width: 1024px)").matches) { vh = `${window.innerHeight}px` document.documentElement.style.setProperty("--vh", vh) } } set100vh() /** * WAI-ARIA toggle aria-expanded */ function updateAriaExpanded(item){ const ariaexpanded = item.getAttribute('aria-expanded') if (ariaexpanded == 'true') { item.setAttribute('aria-expanded', 'false') } else { item.setAttribute('aria-expanded', 'true') } } a11y_ariaexpanded.forEach((item) => { item.addEventListener('click', function () { updateAriaExpanded(this) }) }) /** * Get header height */ function getHeaderHeight(){ document.documentElement.style.setProperty("--header-height", `${header.clientHeight}px`) } getHeaderHeight() /** * Hide header if scrolling down, show if scrolling up */ window.addEventListener('scroll', () => { currentScrollPos = window.scrollY // const currentScrollPos = window.scrollY //if you start scrolling add class if (currentScrollPos > 0 && !menuIsOpen) { body.classList.add('is-scrolled') } else{ body.classList.remove('is-scrolled') } // if scrolling down, hide header and position logo to the left // if scrolling up, show header and logo in initial position if (prevScrollPos > 0 && prevScrollPos < currentScrollPos && !menuIsOpen) { header.classList.add('is-hidden') logo.classList.add('is-visible') overlay.classList.remove('is-active') } else if (prevScrollPos >= currentScrollPos && !menuIsOpen) { header.classList.remove('is-hidden') logo.classList.remove('is-visible') } prevScrollPos = currentScrollPos }) /** * Menu */ function toggleMenuSharedElements(){ if (!menuIsOpen) { body.classList.add('has-menu-toggled') menuBtn.classList.add('is-active') menuBtn.classList.add('is-toggled') overlay.classList.add('is-active') menuIsOpen = true } else { body.classList.remove('has-menu-toggled') menuBtn.classList.remove('is-active') menuBtn.classList.remove('is-toggled') overlay.classList.remove('is-active') menuIsOpen = false } } // when menu is toggled, set margin top based // on scrolled px and restore scroll after menu is closed function setScrolledMarginContent(scrolled){ if (mobileMenuIsOpen || desktopMenuIsOpen) { pageWrapper.style.marginTop = 0 document.body.scrollTop = menuToggledScrollPos document.body.scrollTop = menuToggledScrollPos document.documentElement.scrollTop = menuToggledScrollPos } else { pageWrapper.style.marginTop = `-${scrolled}px` } menuToggledScrollPos = scrolled } function toggleMobileMenu(forceClosing = null){ if (forceClosing) { menuMobile.classList.remove('is-toggled') } else { menuMobile.classList.toggle('is-toggled') } closeAllAccordionMenuItems() // set margin on page wapper // and restore scrolled position when you close menu setScrolledMarginContent(currentScrollPos) menuIsOpen ? mobileMenuIsOpen = true : mobileMenuIsOpen = false } function toggleDesktopMenu(clickedItem = null){ menuItems.forEach((item) => { if (item == clickedItem) { item.classList.add('is-toggled') } else { item.classList.remove('is-toggled') } }) // set margin on page wapper // and restore scrolled position when you close menu setScrolledMarginContent(currentScrollPos) menuIsOpen ? desktopMenuIsOpen = true : desktopMenuIsOpen = false } function toggleMenuWhenResized(){ // if mobile menu is open and window resized to desktop if (mobileMenuIsOpen && isDesktop.matches){ toggleMenuSharedElements() toggleMobileMenu(true) menuIsOpen = false } // if desktop menu is open and window resized to mobile if (desktopMenuIsOpen && !isDesktop.matches){ toggleMenuSharedElements() toggleDesktopMenu() menuIsOpen = false } } function animateMenuItemsOverlay(e, itemOverlay, mouseenter = true){ // Get the bounding rectangle of target const target = e.target const rect = target.getBoundingClientRect() let height = rect.height // Mouse position const y = e.clientY - rect.top const inOutFromTop = (y < height / 2) ? true : false let itemOverlayAnimations let itemTransform if (inOutFromTop && mouseenter) { itemOverlayAnimations = itemOverlay.animate([ {transform: 'translate3d(0, -101%, 0)'}, {transform: 'translate3d(0, 0, 0)'} ], 250) itemTransform = '0%' } else if (inOutFromTop && !mouseenter) { itemOverlayAnimations = itemOverlay.animate([ {transform: 'translate3d(0, 0, 0)'}, {transform: 'translate3d(0, -101%, 0)'} ], 250) itemTransform = '-101%' } else if (!inOutFromTop && mouseenter) { itemOverlayAnimations = itemOverlay.animate([ {transform: 'translate3d(0, 101%, 0)'}, {transform: 'translate3d(0, 0, 0)'} ], 250) itemTransform = '0%' } else if (!inOutFromTop && !mouseenter) { itemTransform = '101%' itemOverlayAnimations = itemOverlay.animate([ {transform: 'translate3d(0, 0, 0)'}, {transform: 'translate3d(0, 101%, 0)'} ], 250) } itemOverlayAnimations.addEventListener('finish', function() { itemOverlay.style.transform = `translate3d(0, ${itemTransform}, 0)`; }) } function openSubMenu(event){ const item = event.target.closest('li') event.preventDefault() if (item.classList.contains('is-toggled')) { toggleMenuSharedElements() toggleDesktopMenu() } else if (desktopMenuIsOpen){ toggleDesktopMenu(this) } else { toggleMenuSharedElements() toggleDesktopMenu(this) } } menuItems.forEach(item => { item.addEventListener('click', openSubMenu) }) menuSubItems.forEach(subItem => { const subItemOverlay = subItem.querySelector('.menu-item-overlay') subItemOverlay.style.transform = 'translate3d(0, -101%, 0)' subItem.addEventListener('mouseenter', function (e) { animateMenuItemsOverlay(e, subItemOverlay) }) subItem.addEventListener('mouseleave', function (e) { animateMenuItemsOverlay(e, subItemOverlay, false) }) }) menuBtn.addEventListener('click', function(){ toggleMenuSharedElements() if (isDesktop.matches) { toggleDesktopMenu() } else { toggleMobileMenu() } }) //close all accordion menu items function closeAllAccordionMenuItems(){ accordionMenuItems.forEach(item => { item.parentElement.parentElement.classList.remove('is-toggled') item.parentElement.parentElement.setAttribute('aria-expanded', 'false') }) } accordionMenuItems.forEach(button => { button.addEventListener('click', function(){ // get <li> const clickedItem = this.parentElement.parentElement // get nesting of clicked item (from button) const nesting = this.getAttribute('data-toggle-menu-items') if (nesting == 0 && clickedItem.classList.contains('is-toggled')) { // if is first level and already opened, // when clicked close all items closeAllAccordionMenuItems() } else { // when you click on item, close other items on same nesting level [...document.querySelectorAll(`[data-toggle-menu-items="${nesting}"]`)].forEach(i=>{if(this != i){i.parentElement.parentElement.classList.remove('is-toggled')}}) // toggle clicked item clickedItem.classList.toggle('is-toggled') } }) }) /** * Back to top */ document.getElementById('backToTop').addEventListener('click', function(){ window.scrollTo({ top: 0, behavior: 'smooth' }) }) /** * Footer observer */ //when footer is in viewport, restore logo position let footerObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if(entry.isIntersecting){ body.classList.add('footer-in-viewport') } else { body.classList.remove('footer-in-viewport') } }) }, { rootMargin: '0px' }) footerObserver.observe(footer) /** * Window resize function callbacks */ const resizeHandler = function(){ // set vh set100vh() // get header height getHeaderHeight() // when resizing disable menu if toggled toggleMenuWhenResized() } window.addEventListener('resize', resizeHandler) /** * Keyboard related functions and events */ document.onkeydown = function(evt) { evt = evt || window.event; var isEscape = false; if ('key' in evt) { isEscape = (evt.key === 'Escape' || evt.key === 'Esc'); } else { isEscape = (evt.keyCode === 27); } // if menu is open and press escape, toggle desktop or mobile menu // based on media query if (isEscape && menuIsOpen) { toggleMenuSharedElements() if (isDesktop.matches) { toggleDesktopMenu() } else { toggleMobileMenu() } } } })