123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- /**
- * @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) => {
- /**
- * Olivero helper functions.
- *
- * @namespace
- */
- Drupal.olivero = {};
- /**
- * 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.olivero.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.olivero.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()) {
- if (pinnedState === true) {
- siteHeaderFixable.classList.add('is-expanded');
- } else {
- siteHeaderFixable.classList.remove('is-expanded');
- }
- 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.olivero.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.olivero.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.
- if (entry.intersectionRatio < 1) {
- fixableElements.forEach((el) => el.classList.add('is-fixed'));
- } else {
- fixableElements.forEach((el) => el.classList.remove('is-fixed'));
- }
- });
- }
- /**
- * 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);
|