clone of olivero for island lives
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

215 lines
6.0 KiB

/**
* @file
* Controls the visibility of desktop navigation.
*
* Shows and hides the desktop navigation based on scroll position and controls
* the functionality of the button that shows/hides the navigation.
*/
/* eslint-disable no-inner-declarations */
((Drupal) => {
/**
* Olives helper functions.
*
* @namespace
*/
Drupal.olives = {};
/**
* Checks if the mobile navigation button is visible.
*
* @return {boolean}
* True if navButtons is hidden, false if not.
*/
function isDesktopNav() {
const navButtons = document.querySelector(
'[data-drupal-selector="mobile-buttons"]',
);
return navButtons
? window.getComputedStyle(navButtons).getPropertyValue('display') ===
'none'
: false;
}
Drupal.olives.isDesktopNav = isDesktopNav;
const stickyHeaderToggleButton = document.querySelector(
'[data-drupal-selector="sticky-header-toggle"]',
);
const siteHeaderFixable = document.querySelector(
'[data-drupal-selector="site-header-fixable"]',
);
/**
* Checks if the sticky header is enabled.
*
* @return {boolean}
* True if sticky header is enabled, false if not.
*/
function stickyHeaderIsEnabled() {
return stickyHeaderToggleButton.getAttribute('aria-checked') === 'true';
}
/**
* Save the current sticky header expanded state to localStorage, and set
* it to expire after two weeks.
*
* @param {boolean} expandedState
* Current state of the sticky header button.
*/
function setStickyHeaderStorage(expandedState) {
const now = new Date();
const item = {
value: expandedState,
expiry: now.getTime() + 20160000, // 2 weeks from now.
};
localStorage.setItem(
'Drupal.olives.stickyHeaderState',
JSON.stringify(item),
);
}
/**
* Toggle the state of the sticky header between always pinned and
* only pinned when scrolled to the top of the viewport.
*
* @param {boolean} pinnedState
* State to change the sticky header to.
*/
function toggleStickyHeaderState(pinnedState) {
if (isDesktopNav()) {
siteHeaderFixable.classList.toggle('is-expanded', pinnedState);
stickyHeaderToggleButton.setAttribute('aria-checked', pinnedState);
setStickyHeaderStorage(pinnedState);
}
}
/**
* Return the sticky header's stored state from localStorage.
*
* @return {boolean}
* Stored state of the sticky header.
*/
function getStickyHeaderStorage() {
const stickyHeaderState = localStorage.getItem(
'Drupal.olives.stickyHeaderState',
);
if (!stickyHeaderState) return false;
const item = JSON.parse(stickyHeaderState);
const now = new Date();
// Compare the expiry time of the item with the current time.
if (now.getTime() > item.expiry) {
// If the item is expired, delete the item from storage and return null.
localStorage.removeItem('Drupal.olives.stickyHeaderState');
return false;
}
return item.value;
}
// Only enable scroll interactivity if the browser supports Intersection
// Observer.
// @see https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js#L19-L21
if (
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype
) {
const fixableElements = document.querySelectorAll(
'[data-drupal-selector="site-header-fixable"], [data-drupal-selector="social-bar-inner"]',
);
function toggleDesktopNavVisibility(entries) {
if (!isDesktopNav()) return;
entries.forEach((entry) => {
// Firefox doesn't seem to support entry.isIntersecting properly,
// so we check the intersectionRatio.
fixableElements.forEach((el) =>
el.classList.toggle('is-fixed', entry.intersectionRatio < 1),
);
});
}
/**
* Gets the root margin by checking for various toolbar classes.
*
* @return {string}
* Root margin for the Intersection Observer options object.
*/
function getRootMargin() {
let rootMarginTop = 72;
const { body } = document;
if (body.classList.contains('toolbar-fixed')) {
rootMarginTop -= 39;
}
if (
body.classList.contains('toolbar-horizontal') &&
body.classList.contains('toolbar-tray-open')
) {
rootMarginTop -= 40;
}
return `${rootMarginTop}px 0px 0px 0px`;
}
/**
* Monitor the navigation position.
*/
function monitorNavPosition() {
const primaryNav = document.querySelector(
'[data-drupal-selector="site-header"]',
);
const options = {
rootMargin: getRootMargin(),
threshold: [0.999, 1],
};
const observer = new IntersectionObserver(
toggleDesktopNavVisibility,
options,
);
if (primaryNav) {
observer.observe(primaryNav);
}
}
if (stickyHeaderToggleButton) {
stickyHeaderToggleButton.addEventListener('click', () => {
toggleStickyHeaderState(!stickyHeaderIsEnabled());
});
}
// If header is pinned open and a header element gains focus, scroll to the
// top of the page to ensure that the header elements can be seen.
const siteHeaderInner = document.querySelector(
'[data-drupal-selector="site-header-inner"]',
);
if (siteHeaderInner) {
siteHeaderInner.addEventListener('focusin', () => {
if (isDesktopNav() && !stickyHeaderIsEnabled()) {
const header = document.querySelector(
'[data-drupal-selector="site-header"]',
);
const headerNav = header.querySelector(
'[data-drupal-selector="header-nav"]',
);
const headerMargin = header.clientHeight - headerNav.clientHeight;
if (window.scrollY > headerMargin) {
window.scrollTo(0, headerMargin);
}
}
});
}
monitorNavPosition();
setStickyHeaderStorage(getStickyHeaderStorage());
toggleStickyHeaderState(getStickyHeaderStorage());
}
})(Drupal);