site_oueb_2/wp-content/themes/zakra/assets/js/navigation.js

339 lines
9.2 KiB
JavaScript
Raw Normal View History

2022-11-22 20:23:31 +01:00
/**
* File navigation.js.
*
* Handles toggling the navigation menu for small screens and enables TAB key
* navigation support for dropdown menus.
*
* @package Zakra
*/
var ZakraNavHelper = {
// Returns first children of a node.
getChildNodes : function ( node ) {
var children = [], child;
for ( child in node.childNodes ) {
if ( node.childNodes.hasOwnProperty( child ) && 1 === node.childNodes[child].nodeType ) {
children.push( node.childNodes[child] );
}
}
return children;
},
offset: function ( el ) {
var rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return {top: rect.top + scrollTop, left: rect.left + scrollLeft}
},
// Calculate the dimension of an element with margin, padding and content.
dimension : function ( el ) {
return parseInt( document.defaultView.getComputedStyle( el, '' ).getPropertyValue( 'width' ) ) + parseInt( document.defaultView.getComputedStyle( el, '' ).getPropertyValue( 'margin-left' ) ) + parseInt( document.defaultView.getComputedStyle( el, '' ).getPropertyValue( 'padding-left' ) ) + parseInt( document.defaultView.getComputedStyle( el, '' ).getPropertyValue( 'padding-right' ) ) + parseInt( document.defaultView.getComputedStyle( el, '' ).getPropertyValue( 'margin-right' ) );
},
getOverflowItems : function ( navLi ) {
navigation.style.flex = '0 0 ' + navUlTempWidth + 'px';
var extraLi = [];
for ( var liCount = 0; liCount < navLi.length; liCount++ ) {
var initialPos, li, posTop;
li = navLi[liCount];
posTop = this.offset( li ).top;
if ( 0 === liCount ) {
initialPos = posTop;
}
if ( posTop > initialPos ) {
if ( ! li.classList.contains( 'tg-menu-item-search' ) && ! li.classList.contains( 'tg-menu-item-cart' ) &&
! li.classList.contains( 'tg-header-button-wrap' ) && ! li.classList.contains( 'tg-menu-extras-wrap' )
) {
extraLi.push( li );
}
}
}
return extraLi;
}
};
window.zakraNavHelper = ZakraNavHelper;
(
function () {
var container, menu, links, i, len;
container = document.getElementById( 'site-navigation' );
if ( ! container ) {
return;
}
menu = container.getElementsByTagName( 'ul' )[0];
menu.setAttribute( 'aria-expanded', 'false' );
if ( -1 === menu.className.indexOf( 'nav-menu' ) ) {
menu.className += ' nav-menu';
}
// Get all the link elements within the menu.
links = menu.getElementsByTagName( 'a' );
// Each time a menu link is focused or blurred, toggle focus.
for ( i = 0, len = links.length; i < len; i++ ) {
links[i].addEventListener( 'focus', toggleFocus, true );
links[i].addEventListener( 'blur', toggleFocus, true );
}
/**
* Sets or removes .focus class on an element.
*/
function toggleFocus() {
var self = this;
// Move up through the ancestors of the current link until we hit .nav-menu.
while ( -1 === self.className.indexOf( 'nav-menu' ) ) {
// On li elements toggle the class .focus.
if ( 'li' === self.tagName.toLowerCase() ) {
if ( -1 !== self.className.indexOf( 'focus' ) ) {
self.className = self.className.replace( ' focus', '' );
} else {
self.className += ' focus';
}
}
self = self.parentElement;
}
}
/**
* Toggles `focus` class to allow submenu access on tablets.
*/
(
function ( container ) {
var touchStartFn, i,
parentLink = container.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ),
supportsPassive = false;;
try {
var opts = Object.defineProperty( {}, 'passive', {
get: function() {
supportsPassive = true;
}
} );
window.addEventListener( "testPassive", null, opts );
window.removeEventListener( "testPassive", null, opts );
} catch (e) {}
if ( 'ontouchstart' in window ) {
touchStartFn = function ( e ) {
var i,
menuItem = this.parentNode;
if ( ! menuItem.classList.contains( 'focus' ) ) {
e.preventDefault();
for ( i = 0; i < menuItem.parentNode.children.length; ++i ) {
if ( menuItem === menuItem.parentNode.children[i] ) {
continue;
}
menuItem.parentNode.children[i].classList.remove( 'focus' );
}
menuItem.classList.add( 'focus' );
} else {
menuItem.classList.remove( 'focus' );
}
};
for ( i = 0; i < parentLink.length; ++i ) {
parentLink[i].addEventListener( 'touchstart', touchStartFn, supportsPassive ? { passive: true } : false );
}
}
}( container )
);
}()
);
/**
* Fixes menu out of viewport
*/
(
function () {
var i, elEvent;
var elWithChildren = document.querySelectorAll( '.tg-primary-menu li.menu-item-has-children, .tg-primary-menu li.page_item_has_children' ),
elCount = elWithChildren.length,
elEvent = isTouchDevice() ? 'touchstart' : 'mouseenter';
/**
* @see https://stackoverflow.com/questions/123999/how-can-i-tell-if-a-dom-element-is-visible-in-the-current-viewport/7557433#7557433
*/
function isElementInViewport( el ) {
var rect = el.getBoundingClientRect();
return (
0 <= rect.left &&
rect.right <= (
( window.innerWidth - 10 ) || ( document.documentElement.clientWidth - 10 )
)
);
}
// Checks whether user uses touch device or not.
function isTouchDevice() {
return 'ontouchstart' in window || navigator.maxTouchPoints;
};
// Loop through li having sub menu.
for ( i = 0; i < elCount; i++ ) {
// On mouse enter.
elWithChildren[i].addEventListener( elEvent, function ( ev ) {
var li = ev.currentTarget,
subMenu;
if ( li ) {
subMenu = li.querySelectorAll( '.sub-menu, .children' )[0];
if ( subMenu ) {
if ( ! isElementInViewport( subMenu ) ) {
subMenu.classList.add( 'tg-edge' );
}
}
}
}, false );
// On mouse leave.
elWithChildren[i].addEventListener( 'mouseleave', function ( ev ) {
var li = ev.currentTarget,
sub;
if ( li ) {
sub = li.querySelectorAll( '.sub-menu, .children' )[0];
sub.classList.remove( 'tg-edge' );
if ( sub.classList.contains( 'tg-edge' ) ) {
sub.classList.remove( 'tg-edge' );
}
}
}, false );
} // End: for ( i in elWithChildren ) {
}
)();
/**
* Keep menu items on one line.
*/
(
function () {
// Get required elements.
var more, search, cart, button, button2, searchWidth, cartWidth, buttonWidth, moreWidth, navUl, navLi,
navLiWidth, extraWrap, navWrapWidth, overflowItems;
navigation = document.getElementById( 'site-navigation' );
// Return if no navigation markup.
if ( null === navigation ) {
return;
}
// Return if `Keep Menu Items on One Line` customizer option is not enabled
if ( ! navigation.classList.contains( 'tg-extra-menus' ) ) {
return;
}
// Extra ellipsis icon added via PHP.
more = navigation.getElementsByClassName( 'tg-menu-extras-wrap' )[0];
// Ul to append extra menu items.
extraWrap = document.getElementById( 'tg-menu-extras' );
// No primary menu assigned.
if ( null === extraWrap ) {
return;
}
navUl = navigation.getElementsByClassName( 'nav-menu' )[0];
navLi = ZakraNavHelper.getChildNodes( navUl );
navWrapWidth = navigation.offsetWidth;
search = navigation.getElementsByClassName( 'tg-menu-item-search' )[0];
cart = navigation.getElementsByClassName( 'tg-menu-item-cart' )[0];
button = navigation.getElementsByClassName( 'tg-header-button-wrap' )[0];
button2 = navigation.getElementsByClassName( 'tg-header-button-wrap' )[1];
searchWidth = search ? ZakraNavHelper.dimension( search ) : 0;
cartWidth = cart ? ZakraNavHelper.dimension( cart ) : 0;
buttonWidth = button ? ZakraNavHelper.dimension( button ) : 0;
buttonWidth += button2 ? ZakraNavHelper.dimension( button2 ) : 0;
moreWidth = more ? ZakraNavHelper.dimension( more ) : 0;
navUlTempWidth = navWrapWidth - ( searchWidth + cartWidth + buttonWidth + moreWidth );
navLiWidth = 0;
navLi.forEach( function ( menuItem, index ) {
navLiWidth += ZakraNavHelper.dimension( menuItem );
} );
// If overflow.
if ( navLiWidth > navWrapWidth ) {
overflowItems = ZakraNavHelper.getOverflowItems( navLi );
overflowItems.forEach( function ( item ) {
extraWrap.appendChild( item );
});
} else {
// Remove ellipsis icon for more.
more.parentNode.removeChild( more );
}
navigation.style.flex = '';
}()
);
/**
* Close mobile menu on clicking menu items.
*/
(
function () {
var mobMenuItems = document.querySelectorAll( '#mobile-navigation li a' ),
toggleButton = document.querySelector( '.tg-mobile-toggle' ),
mobMenuItemsCount = mobMenuItems.length,
item;
for ( var i = 0; i < mobMenuItemsCount; i++ ) {
item = mobMenuItems[i];
item.addEventListener(
'click',
function () {
toggleButton.click();
}
);
}
}()
);