Newer
Older
pre-www / src / assets / js / site.js
/**
 * 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 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) {
        $('html').addClass('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) {
            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 ) {
            header.classList.add('is-hidden')
            logo.classList.add('is-visible')
            overlay.classList.remove('is-active')
        } else if (prevScrollPos >= currentScrollPos) {
            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
        }
    }

    menuItems.forEach(item => {
        item.addEventListener('click', function(e){
            e.preventDefault()
            if (item.classList.contains('is-toggled')) {
                toggleMenuSharedElements()
                toggleDesktopMenu()
            } else if (desktopMenuIsOpen){
                toggleDesktopMenu(this)
            } else {
                toggleMenuSharedElements()
                toggleDesktopMenu(this)
            }
        })
    })
    
    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)

})