From: Dan Allen Date: Fri, 19 Jul 2019 08:31:37 +0000 (-0600) Subject: drop nav state functionality X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=d91f6867ffaa69f52b19f907d7361b618ce44d64;p=working%2Feg-antora.git drop nav state functionality - don't attempt to remember expanded state or scroll offset - scroll current page in nav to midpoint - scroll current page in nav to midpoint when nav is initially hidden - rename 01-navigation.js to 01-nav.js for consistency --- diff --git a/src/css/nav.css b/src/css/nav.css index 471dfee..9ffa5b4 100644 --- a/src/css/nav.css +++ b/src/css/nav.css @@ -1,11 +1,11 @@ .nav-container { - display: none; position: fixed; top: var(--navbar-height); left: 0; width: 100%; font-size: 0.9375rem; z-index: var(--z-index-nav); + visibility: hidden; } @media screen and (min-width: 769px) { @@ -19,14 +19,14 @@ .nav-container { font-size: 0.8125rem; flex: none; - display: block; position: static; top: 0; + visibility: visible; } } .nav-container.is-active { - display: block; + visibility: visible; } .nav { diff --git a/src/js/01-nav.js b/src/js/01-nav.js new file mode 100644 index 0000000..65481b5 --- /dev/null +++ b/src/js/01-nav.js @@ -0,0 +1,106 @@ +;(function () { + 'use strict' + + var navContainer = document.querySelector('.nav-container') + var navToggle = document.querySelector('.nav-toggle') + + navToggle.addEventListener('click', showNav) + // NOTE don't let click events propagate outside of nav container + navContainer.addEventListener('click', concealEvent) + + var menuPanel = navContainer.querySelector('[data-panel=menu]') + if (!menuPanel) return + var nav = navContainer.querySelector('.nav') + + var currentPageItem = menuPanel.querySelector('.is-current-page') + if (currentPageItem) { + activateCurrentPath(currentPageItem) + scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link')) + } else { + menuPanel.scrollTop = 0 + } + + find(menuPanel, '.nav-item-toggle').forEach(function (btn) { + var li = btn.parentElement + btn.addEventListener('click', toggleActive.bind(li)) + var navItemSpan = findNextElement(btn, '.nav-text') + if (navItemSpan) { + navItemSpan.style.cursor = 'pointer' + navItemSpan.addEventListener('click', toggleActive.bind(li)) + } + }) + + nav.querySelector('.context').addEventListener('click', function () { + var currentPanel = nav.querySelector('.is-active[data-panel]') + var activatePanel = currentPanel.dataset.panel === 'menu' ? 'explore' : 'menu' + currentPanel.classList.toggle('is-active') + nav.querySelector('[data-panel=' + activatePanel + ']').classList.toggle('is-active') + }) + + // NOTE prevent text from being selected by double click + menuPanel.addEventListener('mousedown', function (e) { + if (e.detail > 1) e.preventDefault() + }) + + function activateCurrentPath (navItem) { + var ancestorClasses + var ancestor = navItem.parentNode + while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) { + if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) { + ancestorClasses.add('is-active', 'is-current-path') + } + ancestor = ancestor.parentNode + } + navItem.classList.add('is-active') + } + + function toggleActive () { + this.classList.toggle('is-active') + } + + function showNav (e) { + if (navToggle.classList.contains('is-active')) return hideNav(e) + document.documentElement.classList.add('is-clipped--nav') + navToggle.classList.add('is-active') + navContainer.classList.add('is-active') + window.addEventListener('click', hideNav) + concealEvent(e) + } + + function hideNav (e) { + if (e.which === 3 || e.button === 2) return + document.documentElement.classList.remove('is-clipped--nav') + navToggle.classList.remove('is-active') + navContainer.classList.remove('is-active') + window.removeEventListener('click', hideNav) + concealEvent(e) + } + + // NOTE don't let event get picked up by window click listener + function concealEvent (e) { + e.stopPropagation() + } + + function scrollItemToMidpoint (panel, el) { + var rect = panel.getBoundingClientRect() + var effectiveHeight = rect.height + var navStyle = window.getComputedStyle(nav) + if (navStyle.position === 'sticky') effectiveHeight -= (rect.top - parseFloat(navStyle.top)) + panel.scrollTop = Math.max(0, (el.getBoundingClientRect().height - effectiveHeight) * 0.5 + el.offsetTop) + } + + function find (from, selector) { + return [].slice.call(from.querySelectorAll(selector)) + } + + function findNextElement (from, selector) { + var el + if ('nextElementSibling' in from) { + el = from.nextElementSibling + } else { + el = from + while ((el = el.nextSibling) && el.nodeType !== 1); + } + return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el + } +})() diff --git a/src/js/01-navigation.js b/src/js/01-navigation.js deleted file mode 100644 index ba25546..0000000 --- a/src/js/01-navigation.js +++ /dev/null @@ -1,166 +0,0 @@ -;(function () { - 'use strict' - - var navContainer = document.querySelector('.nav-container') - var navToggle = document.querySelector('.nav-toggle') - - navToggle.addEventListener('click', toggleNavigation) - // don't let click events propagate outside of nav container - navContainer.addEventListener('click', concealEvent) - - var menuPanel = navContainer.querySelector('[data-panel=menu]') - if (!menuPanel) return - - var navState = getNavState() - var menuState = getMenuState(navState, navContainer.dataset.component, navContainer.dataset.version) - - navContainer.querySelector('.context').addEventListener('click', function () { - var currentPanel = navContainer.querySelector('.is-active[data-panel]') - var activatePanel = currentPanel.dataset.panel === 'menu' ? 'explore' : 'menu' - currentPanel.classList.toggle('is-active') - navContainer.querySelector('[data-panel=' + activatePanel + ']').classList.toggle('is-active') - }) - - find('.nav-item-toggle', menuPanel).forEach(function (btn) { - var li = btn.parentElement - btn.addEventListener('click', function () { - li.classList.toggle('is-active') - menuState.expandedItems = getExpandedItems() - saveNavState() - }) - var navItemSpan = findNextElement(btn, '.nav-text') - if (navItemSpan) { - navItemSpan.style.cursor = 'pointer' - navItemSpan.addEventListener('click', function () { - li.classList.toggle('is-active') - menuState.expandedItems = getExpandedItems() - saveNavState() - }) - } - }) - - find('.nav-item', menuPanel).forEach(function (item, idx) { - item.setAttribute('data-id', 'menu-' + item.dataset.depth + '-' + idx) - }) - - var expandedItems = menuState.expandedItems || (menuState.expandedItems = []) - - if (expandedItems.length) { - find( - expandedItems - .map(function (itemId) { - return '.nav-item[data-id="' + itemId + '"]' - }) - .join(','), - menuPanel - ).forEach(function (item) { - item.classList.add('is-active') - }) - } - - var currentPageItem = menuPanel.querySelector('.is-current-page') - if (currentPageItem) { - activateCurrentPath(currentPageItem).forEach(function (itemId) { - if (expandedItems.indexOf(itemId) < 0) expandedItems.push(itemId) - }) - } - - saveNavState() - - scrollItemIntoView(menuState.scroll || 0, menuPanel, currentPageItem && currentPageItem.querySelector('.nav-link')) - - menuPanel.addEventListener('scroll', function () { - menuState.scroll = Math.round(menuPanel.scrollTop) - saveNavState() - }) - - function activateCurrentPath (navItem) { - var ids = [navItem.dataset.id] - var ancestorClasses - var ancestor = navItem.parentNode - while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) { - if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) { - ancestorClasses.add('is-active', 'is-current-path') - ids.push(ancestor.dataset.id) - } - ancestor = ancestor.parentNode - } - navItem.classList.add('is-active') - return ids - } - - function toggleNavigation (e) { - if (navToggle.classList.contains('is-active')) return closeNavigation(e) - document.documentElement.classList.add('is-clipped--nav') - navToggle.classList.add('is-active') - navContainer.classList.add('is-active') - window.addEventListener('click', closeNavigation) - // don't let this event get picked up by window click listener - concealEvent(e) - } - - function closeNavigation (e) { - if (e.which === 3 || e.button === 2) return - document.documentElement.classList.remove('is-clipped--nav') - navToggle.classList.remove('is-active') - navContainer.classList.remove('is-active') - window.removeEventListener('click', closeNavigation) - // don't let this event get picked up by window click listener - concealEvent(e) - } - - function concealEvent (e) { - e.stopPropagation() - } - - function getExpandedItems () { - return find('.is-active', menuPanel).map(function (item) { - return item.dataset.id - }) - } - - function getNavState () { - var data = window.sessionStorage.getItem('nav-state') - return data && (data = JSON.parse(data)).__version__ === '1' ? data : { __version__: '1' } - } - - function getMenuState (navState, component, version) { - var key = version + '@' + component - return navState[key] || (navState[key] = {}) - } - - function saveNavState () { - window.sessionStorage.setItem('nav-state', JSON.stringify(navState)) - } - - function scrollItemIntoView (scrollPosition, parent, el) { - if (!el) return (parent.scrollTop = scrollPosition) - - var margin = 10 - //var y = el.getBoundingClientRect().top - parent.getBoundingClientRect().top - var y = el.offsetTop - - if (y < scrollPosition) { - parent.scrollTop = y - margin - } else if (y - parent.offsetHeight + el.offsetHeight > scrollPosition) { - parent.scrollTop = y - parent.offsetHeight + el.offsetHeight + margin - } else { - parent.scrollTop = scrollPosition - } - } - - function find (selector, from) { - return [].slice.call((from || document).querySelectorAll(selector)) - } - - function findNextElement (from, selector) { - var el - if ('nextElementSibling' in from) { - el = from.nextElementSibling - } else { - el = from - while ((el = el.nextSibling) && el.nodeType !== 1); - } - return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el - } -})()