1/** 2 * File fronend.js 3 * 4 * Handles toggling the navigation menu for small screens and enables tab 5 * support for dropdown menus. 6 * 7 * @package Astra 8 */ 9 10/** 11 * Get all of an element's parent elements up the DOM tree 12 * 13 * @param {Node} elem The element. 14 * @param {String} selector Selector to match against [optional]. 15 * @return {Array} The parent elements. 16 */ 17var astraGetParents = function ( elem, selector ) { 18 19 // Setup parents array. 20 var parents = []; 21 22 // Get matching parent elements. 23 for ( ; elem && elem !== document; elem = elem.parentNode ) { 24 25 // Add matching parents to array. 26 if ( selector ) { 27 if ( elem.matches( selector ) ) { 28 parents.push( elem ); 29 } 30 } else { 31 parents.push( elem ); 32 } 33 } 34 return parents; 35}; 36 37 38/** 39 * Toggle Class funtion 40 * 41 * @param {Node} elem The element. 42 * @param {String} selector Selector to match against [optional]. 43 * @return {Array} The parent elements. 44 */ 45var astraToggleClass = function ( el, className ) { 46 if ( el.classList.contains( className ) ) { 47 el.classList.remove( className ); 48 } else { 49 el.classList.add( className ); 50 } 51}; 52 53 54/** 55 * Trigget custom JS Event. 56 * 57 * @since 1.4.6 58 * 59 * @link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent 60 * @param {Node} el Dom Node element on which the event is to be triggered. 61 * @param {Node} typeArg A DOMString representing the name of the event. 62 * @param {String} A CustomEventInit dictionary, having the following fields: 63 * "detail", optional and defaulting to null, of type any, that is an event-dependent value associated with the event. 64 */ 65var astraTriggerEvent = function astraTriggerEvent( el, typeArg ) { 66 var customEventInit = 67 arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 68 69 var event = new CustomEvent(typeArg, customEventInit); 70 el.dispatchEvent(event); 71}; 72 73/** 74 * Scroll to ID/Top with smooth scroll behavior. 75 * 76 * @since x.x.x 77 * 78 * @param {Event} e Event which is been fired. 79 * @param {String} top offset from top. 80 */ 81astraSmoothScroll = function astraSmoothScroll( e, top ) { 82 e.preventDefault(); 83 window.scrollTo({ 84 top: top, 85 left: 0, 86 behavior: 'smooth' 87 }); 88}; 89 90/** 91 * Scroll to Top trigger visibility adjustments. 92 * 93 * @since x.x.x 94 * 95 * @param {Node} masthead Page header. 96 * @param {Node} astScrollTop Scroll to Top selector. 97 */ 98astScrollToTopHandler = function ( masthead, astScrollTop ) { 99 100 var content = getComputedStyle(astScrollTop).content, 101 device = astScrollTop.dataset.onDevices; 102 content = content.replace( /[^0-9]/g, '' ); 103 104 if( 'both' == device || ( 'desktop' == device && '769' == content ) || ( 'mobile' == device && '' == content ) ) { 105 // Get current window / document scroll. 106 var scrollTop = window.pageYOffset || document.body.scrollTop; 107 // If masthead found. 108 if( masthead && masthead.length ) { 109 if (scrollTop > masthead.offsetHeight + 100) { 110 astScrollTop.style.display = "block"; 111 } else { 112 astScrollTop.style.display = "none"; 113 } 114 } else { 115 // If there is no masthead set default start scroll 116 if ( window.pageYOffset > 300 ) { 117 astScrollTop.style.display = "block"; 118 } else { 119 astScrollTop.style.display = "none"; 120 } 121 } 122 } else { 123 astScrollTop.style.display = "none"; 124 } 125}; 126 127( function() { 128 129 var menu_toggle_all = document.querySelectorAll( '#masthead .main-header-menu-toggle' ), 130 main_header_masthead = document.getElementById('masthead'), 131 menu_click_listeners_nav = {}, 132 mobileHeaderType = '', 133 body = document.body, 134 mobileHeader = ''; 135 136 if ( undefined !== main_header_masthead && null !== main_header_masthead ) { 137 138 mobileHeader = main_header_masthead.querySelector("#ast-mobile-header"); 139 } 140 141 if ( '' !== mobileHeader && null !== mobileHeader ) { 142 143 mobileHeaderType = mobileHeader.dataset.type; 144 } 145 146 document.addEventListener( 'astMobileHeaderTypeChange', updateHeaderType, false ); 147 148 /** 149 * Updates the header type. 150 */ 151 function updateHeaderType( e ) { 152 mobileHeaderType = e.detail.type; 153 var popupTrigger = document.querySelectorAll( '.menu-toggle' ); 154 155 if( 'dropdown' === mobileHeaderType ) { 156 157 document.getElementById( 'ast-mobile-popup' ).classList.remove( 'active', 'show' ); 158 updateTrigger('updateHeader'); 159 } 160 161 if ( 'off-canvas' === mobileHeaderType ) { 162 popupTrigger.forEach(function (trigger) { 163 if (trigger && trigger.classList.contains('toggled')) { 164 trigger.click(); 165 } 166 }); 167 } 168 169 init(mobileHeaderType); 170 } 171 172 function syncToggledClass() { 173 const buttons = document.querySelectorAll('.menu-toggle'); 174 const allToggled = Array.from(buttons).every(button => button.classList.contains('toggled')); 175 176 buttons.forEach(button => { 177 if (allToggled) { 178 button.classList.remove('toggled'); 179 button.setAttribute('aria-expanded', 'false'); 180 } else { 181 button.classList.add('toggled'); 182 button.setAttribute('aria-expanded', 'true'); 183 } 184 }); 185 } 186 187 document.addEventListener('click', function (e) { 188 const button = e.target.closest('.menu-toggle'); 189 if (button && mobileHeaderType === 'dropdown') { 190 if (typeof astraAddon === 'undefined') { 191 button.classList.toggle('toggled'); 192 syncToggledClass(); 193 } 194 const isToggled = button.classList.contains('toggled'); 195 button.setAttribute('aria-expanded', isToggled ? 'true' : 'false'); 196 } 197 }); 198 199 200 /** 201 * Opens the Popup when trigger is clicked. 202 */ 203 popupTriggerClick = function ( event ) { 204 205 var triggerType = event.currentTarget.trigger_type; 206 var popupWrap = document.getElementById( 'ast-mobile-popup' ); 207 208 if ( ! body.classList.contains( 'ast-popup-nav-open' ) ) { 209 body.classList.add( 'ast-popup-nav-open' ); 210 } 211 212 if ( ! body.classList.contains( 'ast-main-header-nav-open' ) && 'mobile' !== triggerType ) { 213 body.classList.add( 'ast-main-header-nav-open' ); 214 } 215 216 if ( ! document.documentElement.classList.contains( 'ast-off-canvas-active' ) ) { 217 document.documentElement.classList.add( 'ast-off-canvas-active' ); 218 } 219 220 if ( 'desktop' === triggerType ) { 221 222 popupWrap.querySelector( '.ast-mobile-popup-content' ).style.display = 'none'; 223 popupWrap.querySelector( '.ast-desktop-popup-content' ).style.display = 'block'; 224 } 225 if ( 'mobile' === triggerType ) { 226 227 popupWrap.querySelector( '.ast-desktop-popup-content' ).style.display = 'none'; 228 popupWrap.querySelector( '.ast-mobile-popup-content' ).style.display = 'block'; 229 } 230 if (event && event.currentTarget && event.currentTarget.style) { 231 event.currentTarget.style.display = 'none'; 232 } 233 234 popupWrap.classList.add( 'active', 'show' ); 235 236 const menuToggleClose = document.getElementById( 'menu-toggle-close' ); 237 menuToggleClose?.focus(); 238 } 239 240 /** 241 * Closes the Trigger when Popup is Closed. 242 */ 243 function updateTrigger(currentElement) { 244 mobileHeader = main_header_masthead.querySelector( "#ast-mobile-header" ); 245 var parent_li_sibling = ''; 246 247 if( undefined !== mobileHeader && null !== mobileHeader && 'dropdown' === mobileHeader.dataset.type && 'updateHeader' !== currentElement ) { 248 return; 249 } 250 if ( undefined !== currentElement && 'updateHeader' !== currentElement ) { 251 252 parent_li_sibling = currentElement.closest( '.ast-mobile-popup-inner' ).querySelectorAll('.menu-item-has-children'); 253 254 } else { 255 var popup = document.querySelector( '#ast-mobile-popup' ); 256 parent_li_sibling = popup.querySelectorAll('.menu-item-has-children'); 257 258 } 259 260 parent_li_sibling.forEach((li_sibling) => { 261 li_sibling.classList.remove('ast-submenu-expanded'); 262 263 const all_sub_menu = Array.from(li_sibling.querySelectorAll('.sub-menu')); 264 all_sub_menu.forEach((sub_menu) => { 265 if (!sub_menu.hasAttribute('data-initial-display')) { 266 sub_menu.setAttribute('data-initial-display', window.getComputedStyle(sub_menu).display); 267 } 268 269 if (sub_menu.getAttribute('data-initial-display') === 'block') { 270 sub_menu.style.display = 'block'; 271 } else { 272 sub_menu.style.display = 'none'; 273 } 274 }); 275 }); 276 277 var popupTrigger = document.querySelectorAll( '.menu-toggle' ); 278 279 document.body.classList.remove( 'ast-main-header-nav-open', 'ast-popup-nav-open' ); 280 document.documentElement.classList.remove( 'ast-off-canvas-active' ); 281 282 for ( var item = 0; item < popupTrigger.length; item++ ) { 283 284 popupTrigger[item].classList.remove( 'toggled' ); 285 popupTrigger[item].setAttribute('aria-expanded', 'false'); 286 287 popupTrigger[item].style.display = 'flex'; 288 } 289 } 290
291 /** 292 * Main Init Function. 293 */ 294 function init( mobileHeaderType ) { 295 296 var popupTriggerMobile = document.querySelectorAll( '#ast-mobile-header .menu-toggle' ); 297 var popupTriggerDesktop = document.querySelectorAll( '#ast-desktop-header .menu-toggle' ); 298 299 if ( undefined === mobileHeaderType && null !== main_header_masthead ) { 300 301 mobileHeader = main_header_masthead.querySelector("#ast-mobile-header"); 302 if( mobileHeader ) { 303 mobileHeaderType = mobileHeader.dataset.type; 304 } else { 305 var desktopHeader = main_header_masthead.querySelector("#ast-desktop-header"); 306 if ( desktopHeader ) { 307 308 mobileHeaderType = desktopHeader.dataset.toggleType; 309 } else { 310 return; 311 } 312 } 313 } 314 315 if ( 'off-canvas' === mobileHeaderType ) { 316 var popupClose = document.getElementById( 'menu-toggle-close' ), 317 popupInner = document.querySelector( '.ast-mobile-popup-inner' ); 318 319 if ( undefined === popupInner || null === popupInner ) { 320 return; // if toggel button component is not loaded. 321 } 322 popupLinks = popupInner.getElementsByTagName( 'a' ); 323 324 // --- Focus Trap Implementation Start --- 325 document.removeEventListener( 'keydown', astraOffcanvasTrapTabKey ); 326 327 function astraOffcanvasTrapTabKey( e ) { 328 let popup = document.getElementById( 'ast-mobile-popup' ); 329 if ( ! popup || ! popup.classList.contains( 'active' ) || e.key !== 'Tab' ) { 330 return; 331 } 332 let focusableElements = popupInner.querySelectorAll( 333 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' 334 ); 335 focusableElements = Array.prototype.filter.call( focusableElements, function ( element ) { 336 return ( 337 element.offsetWidth > 0 && element.offsetHeight > 0 && window.getComputedStyle( element ).visibility !== 'hidden' 338 ); 339 } ); 340 if ( focusableElements.length === 0 ) return; 341 let firstElement = focusableElements[ 0 ]; 342 let lastElement = focusableElements[ focusableElements.length - 1 ]; 343 if ( e.shiftKey && document.activeElement === firstElement ) { 344 e.preventDefault(); 345 lastElement.focus(); 346 } else if ( ! e.shiftKey && document.activeElement === lastElement ) { 347 e.preventDefault(); 348 firstElement.focus(); 349 } 350 } 351 document.addEventListener( 'keydown', astraOffcanvasTrapTabKey ); 352 353 // Remove focus trap when menu is closed 354 function removeAstraOffcanvasTrap() { 355 document.removeEventListener( 'keydown', astraOffcanvasTrapTabKey ); 356 } 357 if ( popupClose ) { 358 popupClose.addEventListener( 'click', removeAstraOffcanvasTrap ); 359 } 360 document.addEventListener( 'keyup', function ( event ) { 361 if ( event.key === 'Escape' ) { 362 removeAstraOffcanvasTrap(); 363 } 364 } ); 365 document.addEventListener( 'click', function ( event ) { 366 let target = event.target; 367 let modal = document.querySelector( '.ast-mobile-popup-drawer.active .ast-mobile-popup-overlay' ); 368 if ( target === modal ) { 369 removeAstraOffcanvasTrap(); 370 } 371 } ); 372 373 for ( var item = 0; item < popupTriggerMobile.length; item++ ) { 374 popupTriggerMobile[ item ].removeEventListener( 'click', astraNavMenuToggle, false ); 375 // Open the Popup when click on trigger 376 popupTriggerMobile[ item ].removeEventListener( 'click', popupTriggerClick ); 377 popupTriggerMobile[ item ].addEventListener( 'click', function(event) { 378 event.currentTarget.setAttribute('aria-expanded', 'true'); 379 popupTriggerClick(event); 380 const menu = document.querySelector('.ast-mobile-popup-drawer.active'); 381 if (!menu) { 382 removeAstraOffcanvasTrap(); 383 } 384 }, false ); 385 popupTriggerMobile[ item ].trigger_type = 'mobile'; 386 } 387 for ( var item = 0; item < popupTriggerDesktop.length; item++ ) { 388 popupTriggerDesktop[ item ].removeEventListener( 'click', astraNavMenuToggle, false ); 389 // Open the Popup when click on trigger 390 popupTriggerDesktop[ item ].removeEventListener( 'click', popupTriggerClick ); 391 popupTriggerDesktop[ item ].addEventListener( 'click', function(event) { 392 event.currentTarget.setAttribute('aria-expanded', 'true'); 393 popupTriggerClick(event); 394 }, false ); 395 popupTriggerDesktop[ item ].trigger_type = 'desktop'; 396 } 397 398 // Getting menu toggle button element. 399 const menuToggleButton = document.querySelector( '.ast-button-wrap .menu-toggle' ); 400 401 //Close Popup on CLose Button Click. 402 popupClose.addEventListener( 'click', function ( e ) { 403 document.getElementById( 'ast-mobile-popup' ).classList.remove( 'active', 'show' ); 404 updateTrigger( this ); 405 // Don't focus if we're in an iframe (e.g., Beaver Builder editor) 406 if ( window.self === window.top ) { 407 menuToggleButton?.focus(); 408 } 409 } ); 410 411 // Close Popup if esc is pressed. 412 document.addEventListener( 'keyup', function ( event ) { 413 if ( event.key === 'Escape' ) { 414 event.preventDefault(); 415 document.getElementById( 'ast-mobile-popup' ).classList.remove( 'active', 'show' ); 416 updateTrigger(); 417 menuToggleButton?.focus(); 418 } 419 } ); 420 421 // Close Popup on outside click. 422 document.addEventListener( 'click', function ( event ) { 423 var target = event.target; 424 var modal = document.querySelector( '.ast-mobile-popup-drawer.active .ast-mobile-popup-overlay' ); 425 if ( target === modal ) { 426 document.getElementById( 'ast-mobile-popup' ).classList.remove( 'active', 'show' ); 427 updateTrigger(); 428 menuToggleButton?.focus(); 429 } 430 } ); 431 432 // Close Popup on # link click inside Popup. 433 for ( let link = 0, len = popupLinks.length; link < len; link++ ) { 434 if ( 435 null !== popupLinks[ link ].getAttribute( 'href' ) && 436 ( popupLinks[ link ].getAttribute( 'href' ).startsWith( '#' ) || 437 -1 !== popupLinks[ link ].getAttribute( 'href' ).search( '#' ) ) && 438 ( ! popupLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) || 439 ( popupLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) && 440 document.querySelector( 'header.site-header' ).classList.contains( 'ast-builder
440-menu-toggle-icon' ) ) ) 441 ) { 442 popupLinks[ link ].addEventListener( 'click', triggerToggleClose, true ); 443 popupLinks[ link ].headerType = 'off-canvas'; 444 } 445 } 446 447 AstraToggleSetup(); 448 } else if ( 'dropdown' === mobileHeaderType ) { 449 450 var mobileDropdownContent = document.querySelectorAll( '.ast-mobile-header-content' ) || false, 451 desktopDropdownContent = document.querySelector( '.ast-desktop-header-content' ) || false; 452 453 // Close Popup on # link click inside Popup. 454 if ( mobileDropdownContent.length > 0 ) { 455 for ( let index = 0; index < mobileDropdownContent.length; index++ ) { 456 var mobileLinks = mobileDropdownContent[ index ].getElementsByTagName( 'a' ); 457 for ( link = 0, len = mobileLinks.length; link < len; link++ ) { 458 // Check if the link is not inside the tabs container 459 const isNotInsideTabsContainer = mobileLinks[ link ].closest( '.wp-block-uagb-tabs' ) === null; 460 461 if ( 462 null !== mobileLinks[ link ].getAttribute( 'href' ) && 463 ( mobileLinks[ link ].getAttribute( 'href' ).startsWith( '#' ) || 464 -1 !== mobileLinks[ link ].getAttribute( 'href' ).search( '#' ) ) && 465 ( ! mobileLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) || 466 ( mobileLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) && 467 document.querySelector( 'header.site-header' ).classList.contains( 'ast-builder-menu-toggle-icon' ) ) ) && 468 isNotInsideTabsContainer 469 ) { 470 mobileLinks[ link ].addEventListener( 'click', triggerToggleClose, true ); 471 mobileLinks[ link ].headerType = 'dropdown'; 472 } 473 } 474 } 475 } 476 477 // Close Popup on # link click inside Popup. 478 if ( desktopDropdownContent ) { 479 var desktopLinks = desktopDropdownContent.getElementsByTagName( 'a' ); 480 for ( link = 0, len = desktopLinks.length; link < len; link++ ) { 481 desktopLinks[ link ].addEventListener( 'click', triggerToggleClose, true ); 482 desktopLinks[ link ].headerType = 'dropdown'; 483 } 484 } 485 486 for ( var item = 0; item < popupTriggerMobile.length; item++ ) { 487 popupTriggerMobile[ item ].removeEventListener( 'click', popupTriggerClick, false ); 488 popupTriggerMobile[ item ].removeEventListener( 'click', astraNavMenuToggle ); 489 popupTriggerMobile[ item ].addEventListener( 'click', astraNavMenuToggle, false ); 490 popupTriggerMobile[ item ].trigger_type = 'mobile'; 491 } 492 for ( var item = 0; item < popupTriggerDesktop.length; item++ ) { 493 popupTriggerDesktop[ item ].removeEventListener( 'click', popupTriggerClick, false ); 494 popupTriggerDesktop[ item ].removeEventListener( 'click', astraNavMenuToggle ); 495 popupTriggerDesktop[ item ].addEventListener( 'click', astraNavMenuToggle, false ); 496 popupTriggerDesktop[ item ].trigger_type = 'desktop'; 497 } 498 499 AstraToggleSetup(); 500 } 501 502 } 503 504 function triggerToggleClose( event ) { 505 506 var headerType = event.currentTarget.headerType; 507 508 switch( headerType ) { 509 510 case 'dropdown': 511 512 var popupTrigger = document.querySelectorAll( '.menu-toggle.toggled' ); 513 514 for ( var item = 0; item < popupTrigger.length; item++ ) { 515 516 popupTrigger[item].click(); 517 } 518 break; 519 case 'off-canvas': 520 521 var popupClose = document.getElementById( 'menu-toggle-close' ); 522 523 popupClose.click(); 524 break; 525 default: 526 break; 527 } 528 } 529 530 window.addEventListener( 'load', function() { 531 init(); 532 } ); 533 document.addEventListener( 'astLayoutWidthChanged', function() { 534 init(); 535 } ); 536 537 document.addEventListener( 'astPartialContentRendered', function() { 538 539 menu_toggle_all = document.querySelectorAll( '.main-header-menu-toggle' ); 540 541 body.classList.remove("ast-main-header-nav-open"); 542 543 document.addEventListener( 'astMobileHeaderTypeChange', updateHeaderType, false ); 544 545 init(); 546 547 } ); 548 549 var mobile_width = ( null !== navigator.userAgent.match(/Android/i) && 'Android' === navigator.userAgent.match(/Android/i)[0] ) ? window.visualViewport.width : window.innerWidth; 550 551 function AstraHandleResizeEvent() { 552 553 var menu_offcanvas_close = document.getElementById('menu-toggle-close'); 554 var menu_dropdown_close = document.querySelector('.menu-toggle.toggled'); 555 var desktop_header_content = document.querySelector('#masthead > #ast-desktop-header .ast-desktop-header-content'); 556 var elementor_editor = document.querySelector('.elementor-editor-active'); 557 558 if ( desktop_header_content ) { 559 desktop_header_content.style.display = 'none'; 560 } 561 var mobileResizeWidth = ( null !== navigator.userAgent.match(/Android/i) && 'Android' === navigator.userAgent.match(/Android/i)[0] ) ? window.visualVie
561wport.width : window.innerWidth; 562 563 if ( mobileResizeWidth !== mobile_width ) { 564 if ( menu_dropdown_close && null === elementor_editor ) { 565 menu_dropdown_close.click(); 566 } 567 document.body.classList.remove( 'ast-main-header-nav-open', 'ast-popup-nav-open' ); 568 569 if( menu_offcanvas_close && null == elementor_editor ) { 570 menu_offcanvas_close.click(); 571 } 572 } 573 574 updateHeaderBreakPoint(); 575 576 AstraToggleSetup(); 577 578 } 579 580 window.addEventListener('resize', function(){ 581 // Skip resize event when keyboard display event triggers on devices. 582 if( 'INPUT' !== document.activeElement.tagName ) { 583 AstraHandleResizeEvent(); 584 } 585 } ); 586 587 document.addEventListener('DOMContentLoaded', function () { 588 AstraToggleSetup(); 589 /** 590 * Navigation Keyboard Navigation. 591 */ 592 var containerButton; 593 if ( body.classList.contains('ast-header-break-point') ) { 594 containerButton = document.getElementById( 'ast-mobile-header' ); 595 } else { 596 containerButton = document.getElementById( 'ast-desktop-header' ); 597 } 598 599 if( null !== containerButton ) { 600 var containerMenu = containerButton.querySelector( '.navigation-accessibility' ); 601 navigation_accessibility( containerMenu, containerButton ); 602 } 603 }); 604 605 var get_window_width = function () { 606 607 return window.innerWidth; 608 } 609 610 /* Add break point Class and related trigger */ 611 var updateHeaderBreakPoint = function () { 612 613 var ww = get_window_width(); 614 615 var break_point = astra.break_point; 616 617 /** 618 * Use matchMedia to evaluate the breakpoint using the same CSS engine that 619 * evaluates media queries. This guarantees JS and CSS always agree on which 620 * header should be visible, eliminating any sub-pixel or scrollbar-width 621 * mismatch between window.innerWidth and the actual CSS viewport width. 622 * 623 * The 0.99 offset mirrors the max-width: (break_point + 0.99)px rule used 624 * in the PHP dynamic CSS, so the transition point is identical in both. 625 * 626 * The 0 === ww guard handles a Chrome edge case where innerWidth returns 0 627 * when opening a URL via "Open in New Tab" — force desktop mode in that case. 628 */ 629 var isMobile = window.matchMedia( '(max-width: ' + ( parseFloat( break_point ) + 0.99 ) + 'px)' ).matches; 630 631 if ( ! isMobile || 0 === ww ) { 632 //remove menu toggled class. 633 if ( menu_toggle_all.length > 0 ) { 634 635 for (var i = 0; i < menu_toggle_all.length; i++) { 636 637 if( null !== menu_toggle_all[i] ) { 638 menu_toggle_all[i].classList.remove('toggled'); 639 } 640 } 641 } 642 body.classList.remove("ast-header-break-point"); 643 body.classList.add("ast-desktop"); 644 astraTriggerEvent(body, "astra-header-responsive-enabled"); 645 646 } else { 647 648 body.classList.add("ast-header-break-point"); 649 body.classList.remove("ast-desktop"); 650 astraTriggerEvent(body, "astra-header-responsive-disabled") 651 } 652 } 653 654 updateHeaderBreakPoint(); 655 body.classList.add( 'ast-header-loaded' ); 656 657 AstraToggleSubMenu = function( event ) { 658 659 event.preventDefault(); 660 661 662 if ('false' === event.target.getAttribute('aria-expanded') || ! event.target.getAttribute('aria-expanded')) { 663 event.target.setAttribute('aria-expanded', 'true'); 664 } else { 665 event.target.setAttribute('aria-expanded', 'false'); 666 } 667 668 var parent_li = this.parentNode; 669 670 if ( parent_li.classList.contains('ast-submenu-expanded') && document.querySelector('header.site-header').classList.contains('ast-builder-menu-toggle-link') ) { 671 672 if (!this.classList.contains('ast-menu-toggle')) { 673 674 var link = parent_li.querySelector('a').getAttribute('href'); 675 if ( '' !== link && '#' !== link) { 676 window.location = link; 677 } 678 } 679 } 680 681 var parent_li_child = parent_li.querySelectorAll('.menu-item-has-children'); 682 for (var j = 0; j < parent_li_child.length; j++) { 683 684 parent_li_child[j].classList.remove('ast-submenu-expanded'); 685 var parent_li_child_sub_menu = parent_li_child[j].querySelector('.sub-menu, .children'); 686 if( null !== parent_li_child_sub_menu ) { 687 parent_li_child_sub_menu.style.display = 'none'; 688 } 689 } 690 691 var parent_li_sibling = parent_li.parentNode.querySelectorAll('.menu-item-has-children'); 692 for (var j = 0; j < parent_li_sibling.length; j++) { 693 694 if (parent_li_sibling[j] != parent_li) { 695 696 parent_li_sibling[j].classList.remove('ast-submenu-expanded'); 697 var all_sub_menu = parent_li_sibling[j].querySelectorAll('.sub-menu'); 698 for (var k = 0; k < all_sub_menu.length; k++) { 699 all_sub_menu[k].style.display = 'none'; 700 } 701 } 702 } 703 704 if (parent_li.classList.contains('menu-item-has-children') ) { 705 astraToggleClass(parent_li, 'ast-submenu-expanded'); 706 if (parent_li.classList.contains('ast-submenu-expanded')) { 707 parent_li.querySelector('.sub-menu').style.display = 'block'; 708 } else { 709 parent_li.querySelector('.sub-menu').style.display = 'none'; 710 } 711 } 712 }; 713 714 AstraToggleSetup = function () { 715 716 if( typeof astraAddon != 'undefined' && typeof astraToggleSetupPro === "function" ) { 717 astraToggleSetupPro( mobileHeaderType, body, menu_click_listeners_nav ); 718 } else { 719 var flag = false;
720 var menuToggleAllLength; 721 if ( 'off-canvas' === mobileHeaderType || 'full-width' === mobileHeaderType ) { 722 // comma separated selector added, if menu is outside of Off-Canvas then submenu is not clickable, it work only for Off-Canvas area with dropdown style. 723 var __main_header_all = document.querySelectorAll( '#ast-mobile-popup, #ast-mobile-header' ); 724 var menu_toggle_all = document.querySelectorAll('#ast-mobile-header .main-header-menu-toggle'); 725 726 menuToggleAllLength = menu_toggle_all.length; 727 } else { 728 var __main_header_all = document.querySelectorAll( '#ast-mobile-header' ), 729 menu_toggle_all = document.querySelectorAll('#ast-mobile-header .main-header-menu-toggle'); 730 menuToggleAllLength = menu_toggle_all.length; 731 flag = menuToggleAllLength > 0 ? false : true; 732 733 menuToggleAllLength = flag ? 1 : menuToggleAllLength; 734 735 } 736 737 if ( menuToggleAllLength > 0 || flag ) { 738 739 for (var i = 0; i < menuToggleAllLength; i++) { 740 741 if ( ! flag ) { 742 743 menu_toggle_all[i].setAttribute('data-index', i); 744 745 if ( ! menu_click_listeners_nav[i] ) { 746 menu_click_listeners_nav[i] = menu_toggle_all[i]; 747 menu_toggle_all[i].removeEventListener('click', astraNavMenuToggle); 748 menu_toggle_all[i].addEventListener('click', astraNavMenuToggle, false); 749 } 750 } 751 752 if ('undefined' !== typeof __main_header_all[i]) { 753 754 // To handle the comma seprated selector added above we need this loop. 755 for( var mainHeaderCount =0; mainHeaderCount < __main_header_all.length; mainHeaderCount++ ){ 756 757 if (document.querySelector('header.site-header').classList.contains('ast-builder-menu-toggle-link')) { 758 var astra_menu_toggle = __main_header_all[mainHeaderCount].querySelectorAll('ul.main-header-menu .menu-item-has-children > .menu-link, ul.main-header-menu .ast-menu-toggle'); 759 } else { 760 var astra_menu_toggle = __main_header_all[mainHeaderCount].querySelectorAll('ul.main-header-menu .ast-menu-toggle'); 761 } 762 // Add Eventlisteners for Submenu. 763 if (astra_menu_toggle.length > 0) { 764 765 for (var j = 0; j < astra_menu_toggle.length; j++) { 766 astra_menu_toggle[j].removeEventListener('click', AstraToggleSubMenu); 767 astra_menu_toggle[j].addEventListener('click', AstraToggleSubMenu, false); 768 } 769 } 770 } 771 } 772 } 773 } 774 } 775 }; 776 777 astraNavMenuToggle = function ( event ) { 778 779 if( typeof astraAddon != 'undefined' ) { 780 astraNavMenuTogglePro( event, body, mobileHeaderType, this ); 781 } else { 782 783 event.preventDefault(); 784 var __main_header_all = document.querySelectorAll('#masthead > #ast-mobile-header .main-header-bar-navigation'); 785 menu_toggle_all = document.querySelectorAll( '#masthead > #ast-mobile-header .main-header-menu-toggle' ) 786 var event_index = '0'; 787 788 if ( null !== this.closest( '#ast-fixed-header' ) ) { 789 790 __main_header_all = document.querySelectorAll('#ast-fixed-header > #ast-mobile-header .main-header-bar-navigation'); 791 menu_toggle_all = document.querySelectorAll( '#ast-fixed-header .main-header-menu-toggle' ) 792 793 event_index = '0'; 794 } 795 796 if ('undefined' === typeof __main_header_all[event_index]) { 797 return false; 798 } 799 var menuHasChildren = __main_header_all[event_index].querySelectorAll('.menu-item-has-children'); 800 for (var i = 0; i < menuHasChildren.length; i++) { 801 menuHasChildren[i].classList.remove('ast-submenu-expanded'); 802 var menuHasChildrenSubMenu = menuHasChildren[i].querySelectorAll('.sub-menu'); 803 for (var j = 0; j < menuHasChildrenSubMenu.length; j++) { 804 menuHasChildrenSubMenu[j].style.display = 'none'; 805 } 806 } 807 808 var menu_class = this.getAttribute('class') || ''; 809 810 if ( menu_class.indexOf('main-header-menu-toggle') !== -1 ) { 811 astraToggleClass(__main_header_all[event_index], 'toggle-on'); 812 astraToggleClass(menu_toggle_all[event_index], 'toggled'); 813 if (__main_header_all[event_index].classList.contains('toggle-on')) { 814 __main_header_all[event_index].style.display = 'block'; 815 body.classList.add("ast-main-header-nav-open"); 816 } else { 817 __main_header_all[event_index].style.display = ''; 818 body.classList.remove("ast-main-header-nav-open"); 819 } 820 } 821 } 822 }; 823 824 body.addEventListener("astra-header-responsive-enabled", function () { 825 826 var __main_header_all = document.querySelectorAll('.main-header-bar-navigation'); 827 828 if (__main_header_all.length > 0) { 829 830 for (var i = 0; i < __main_header_all.length; i++) { 831 if (null != __main_header_all[i]) { 832 __main_header_all[i].classList.remove('toggle-on'); 833 __main_header_all[i].style.display = ''; 834 } 835 836 var sub_menu = __main_header_all[i].getElementsByClassName('sub-menu'); 837 for (var j = 0; j < sub_menu.length; j++) { 838 sub_menu[j].style.display = ''; 839 } 840 var child_menu = __main_header_all[i].getElementsByClassName('children'); 841 for (var k = 0; k < child_menu.length; k++) { 842 child_menu[k].style.display = ''; 843 } 844 845 var searchIcons = __main_header_all[i].getElementsByClassName('ast-search-menu-icon'); 846 for (var l = 0; l < searchIcons.length; l++) { 847 searchIcons[l].classList.remove('ast-dropdown-active'); 848 searchIcons[l].style.display = ''; 849 } 850 } 851 } 852 }, false); 853 854 855 /* Search Script */ 856 var SearchIcons = document.getElementsByClassName( 'astra-search-icon' ); 857 for (var i = 0; i < SearchIcons.length; i++) { 858 859 SearchIcons[i].onclick = function(event) { 860 if ( this.classList.contains( 'slide-search' ) ) { 861 event.preventDefault(); 862 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 863 if ( ! sibling.classList.contains( 'ast-dropdown-active' ) ) { 864 sibling.classList.add( 'ast-dropdown-active' ); 865 sibling.querySelector( '.search-field' ).setAttribute('autocomplete','off'); 866 setTimeout(function() { 867 sibling.querySelector( '.search-field' ).focus(); 868 },200); 869 } else { 870 var searchTerm = sibling.querySelector( '.search-field' ).value || ''; 871 if( '' !== searchTerm ) { 872 sibling.querySelector( '.search-form' ).submit(); 873 } 874 sibling.classList.remove( 'ast-dropdown-active' ); 875 } 876 } 877 } 878 } 879 var SearchInputs = document.querySelectorAll( '.search-field' );
880 SearchInputs.forEach(input => { 881 input.addEventListener('focus', function (e) { 882 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 883 if ( sibling ) { 884 astraToggleClass( sibling, 'ast-dropdown-active' ); 885 } 886 }); 887 input.addEventListener('blur', function (e) { 888 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 889 if ( sibling ) { 890 sibling.classList.remove( 'ast-dropdown-active' ); 891 astraToggleClass( sibling, 'ast-dropdown-active' ); 892 } 893 }); 894 }); 895 896 /* Hide Dropdown on body click*/ 897 body.onclick = function( event ) { 898 if ( typeof event.target.classList !== 'undefined' ) { 899 if ( ! event.target.classList.contains( 'ast-search-menu-icon' ) && ! event.target.closest( '.ast-search-menu-icon' ) && ! event.target.closest( '.ast-search-icon' ) ) { 900 var dropdownSearchWrap = document.getElementsByClassName( 'ast-search-menu-icon' ); 901 for (var i = 0; i < dropdownSearchWrap.length; i++) { 902 dropdownSearchWrap[i].classList.remove( 'ast-dropdown-active' ); 903 } 904 } 905 } 906 } 907 908 /** 909 * Navigation Keyboard Navigation. 910 */ 911 function navigation_accessibility(containerMenu, containerButton) { 912 if (!containerMenu || !containerButton) { 913 return; 914 } 915 var button = containerButton.getElementsByTagName('button')[0] || containerButton.getElementsByTagName('a')[0]; 916 if (!button || (button.classList.contains('astra-search-icon'))) { 917 return; 918 } 919 var menu = containerMenu.getElementsByTagName('ul')[0]; 920 921 // Hide menu toggle button if menu is empty and return early. 922 if (!menu) { 923 if (!button.classList.contains('custom-logo-link')) { 924 button.style.display = 'none'; 925 } 926 return; 927 } 928 929 if (!menu.className.includes('nav-menu')) { 930 menu.className += ' nav-menu'; 931 } 932 933 document.addEventListener('DOMContentLoaded', function () { 934 if ('off-canvas' === mobileHeaderType) { 935 var popupClose = document.getElementById('menu-toggle-close'); 936 if (popupClose) { 937 popupClose.onclick = function () { 938 var toggled = containerMenu.className.includes('toggled'); 939 containerMenu.className = toggled ? containerMenu.className.replace(' toggled', '') : containerMenu.className + ' toggled'; 940 button.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 941 menu.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 942 }; 943 } 944 } 945 }); 946 947 button.onclick = function () { 948 var toggled = containerMenu.className.includes('toggled'); 949 containerMenu.className = toggled ? containerMenu.className.replace(' toggled', '') : containerMenu.className + ' toggled'; 950 button.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 951 menu.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 952 }; 953 954 if (!astra.is_header_footer_builder_active) { 955 956 // Get all the link elements within the menu. 957 var links = menu.getElementsByTagName('a'); 958 var subMenus = menu.getElementsByTagName('ul'); 959 960 // Set menu items with submenus to aria-haspopup="true". 961 for (var i = 0, len = subMenus.length; i < len; i++) { 962 subMenus[i].parentNode.setAttribute('aria-haspopup', 'true'); 963 } 964 965 // Each time a menu link is focused or blurred, toggle focus. 966 for (var i = 0, len = links.length; i < len; i++) { 967 links[i].addEventListener('focus', toggleFocus, true); 968 links[i].addEventListener('blur', toggleFocus, true); 969 links[i].addEventListener('click', toggleClose, true); 970 } 971 } 972 973 if (astra.is_header_footer_builder_active) { 974 tabNavigation(); 975 } 976 } 977 978 // Tab navigation for accessibility. 979 function tabNavigation() { 980 const dropdownToggleLinks = document.querySelectorAll('nav.site-navigation .menu-item-has-children > a .ast-header-navigation-arrow'); 981 const siteNavigationSubMenu = document.querySelectorAll('nav.site-navigation .sub-menu'); 982 const menuLi = document.querySelectorAll('nav.site-navigation .menu-item-has-children'); 983 const megaMenuFullWidth = document.querySelectorAll('.astra-full-megamenu-wrapper'); 984 985 if (dropdownToggleLinks) { 986 dropdownToggleLinks.forEach(element => { 987 element.addEventListener('keydown', function (e) { 988 if ('Enter' === e.key || ' ' === e.key) { 989 // Check if the user is on a mobile device and prevent default and stop propagation if true. 990 if ( /Mobi|Android|iPad|iPhone/i.test( navigator.userAgent ) ) { 991 e.preventDefault(); 992 e.stopPropagation(); 993 } 994 995 const closestLi = e.target.closest('li'); 996 const subMenu = closestLi.querySelector('.sub-menu'); 997 const isMegaMenu = subMenu && subMenu.classList.contains('astra-megamenu'); 998 999 setTimeout(() => { 1000 if (!isMegaMenu) { 1001 subMenu.classList.toggle('toggled-on'); 1002 closestLi.classList.toggle('ast-menu-hover'); 1003 } else { 1004 const fullMegaMenuWrapper = closestLi.querySelector('.astra-full-megamenu-wrapper'); 1005 if (subMenu) subMenu.classList.toggle('astra-megamenu-focus'); 1006 if (fullMegaMenuWrapper) fullMegaMenuWrapper.classList.toggle('astra-megamenu-wrapper-focus'); 1007 closestLi.classList.toggle('ast-menu-hover'); 1008 } 1009 1010 const ariaExpanded = e.target.getAttribute('aria-expanded'); 1011 e.target.setAttribute('aria-expanded', ariaExpanded === 'false' || !ariaExpanded ? 'true' : 'false'); 1012 }, 10); 1013 } 1014 }); 1015 }); 1016 1017 if (siteNavigationSubMenu || menuLi) { 1018 document.addEventListener('click', function (e) { 1019 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1020 }, false); 1021 1022 document.addEventListener('keydown', function (e) { 1023 if ('Escape' === e.key) { 1024 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1025 } 1026 }, false); 1027 } 1028 } 1029 1030 const allParentMenu = document.querySelectorAll('nav.site-navigation .ast-nav-menu > .menu-item-has-children > a .ast-header-navigation-arrow'); 1031 1032 if (allParentMenu) { 1033 allParentMenu.forEach(element => { 1034 element.addEventListener('keydown', function (e) { 1035 if (!e.target.closest('li').classList.contains('ast-menu-hover') && 'Enter' === e.key) { 1036 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1037 } 1038 }, false); 1039 }); 1040 } 1041 1042 const desktopMenu = document.querySelectorAll( '#ast-desktop-header .ast-builder
1042-layout-element.ast-builder-menu' ); 1043 desktopMenu.forEach( menu => { 1044 const desktopMenuItems = menu.querySelectorAll( '.main-header-menu .menu-item > a' ); 1045 desktopMenuItems.forEach( ( item ) => { 1046 item.addEventListener( 'focusout', function( e ) { 1047 const nextFocus = e.relatedTarget; 1048 const nextFocusMenuItem = nextFocus ? nextFocus.closest( '.menu-item' ) : null; 1049 const currentFocus = e.target; 1050 const currentMenuItem = currentFocus.closest( '.menu-item' ); 1051 const subMenuOpened = currentMenuItem.classList.contains( 'ast-menu-hover' ); 1052 const subMenu = currentMenuItem.querySelector( '.sub-menu' ); 1053 const wrapperSubmenu = currentMenuItem.closest('.sub-menu') 1054 const parentMenuItem = currentMenuItem.closest('.sub-menu')?.closest( '.menu-item-has-children' ); 1055 const childMenuItem = currentMenuItem.querySelector( '.menu-item' ); 1056 1057 1058 // If the next focus is the same menu item or a child menu item, don't close the submenu. 1059 if ( 1060 currentMenuItem == nextFocusMenuItem || 1061 ( childMenuItem && childMenuItem == nextFocusMenuItem ) 1062 ) { 1063 return; 1064 } 1065 1066 // If there's no next focus, close all submenus. 1067 if( nextFocusMenuItem == null ) { 1068 if ( wrapperSubmenu ) 1069 recursiveMenuCloseOnblur( wrapperSubmenu ); 1070 if ( subMenu ) 1071 recursiveMenuCloseOnblur( subMenu ); 1072 return; 1073 } 1074 1075 // If the next focus is the next or previous sibling, don't close all the submenu. 1076 if ( 1077 currentMenuItem.nextElementSibling == nextFocusMenuItem || 1078 currentMenuItem.previousElementSibling == nextFocusMenuItem 1079 ) { 1080 // If the submenu is opened, close it and remove the 'ast-menu-hover' class. 1081 if( subMenuOpened ) { 1082 recursiveMenuCloseOnblur( subMenu, false ); 1083 currentMenuItem.classList.remove( 'ast-menu-hover' ); 1084 } 1085 return; 1086 } 1087 1088 // If the next focus is the parent menu item, close the submenu till the inner child menu item submenu 1089 if ( parentMenuItem && parentMenuItem == nextFocusMenuItem ) { 1090 childSubMenu = currentMenuItem.querySelector( '.sub-menu' ); 1091 recursiveMenuCloseOnblur( childSubMenu, false ); 1092 return; 1093 } 1094 1095 // Here we are setting a depth level point while traversing from lower to upper submenu parents. 1096 // The next focus is the next sibling of any of the parent elements in the tree, then close submenus till that level. 1097 let tempParent = parentMenuItem; 1098 let subMenuCloseEnd = null; 1099 while ( tempParent != null ) { 1100 if( tempParent.nextElementSibling == nextFocusMenuItem ) { 1101 subMenuCloseEnd = tempParent.querySelector( '.sub-menu' ); 1102 break; 1103 } 1104 tempParent = tempParent.closest('.sub-menu')?.closest( '.menu-item-has-children' ); 1105 } 1106 1107 // Closes all the menus. 1108 if( wrapperSubmenu ) 1109 recursiveMenuCloseOnblur( wrapperSubmenu, true, subMenuCloseEnd ); 1110 1111 }); 1112 }); 1113 }); 1114 } 1115 1116 // Recursively closes the submenu upwards 1117 function recursiveMenuCloseOnblur( submenu, recursive = true, bubblingEnd = null ) { 1118 /** 1119 * Close the submenu 1120 */ 1121 submenu.classList.remove( 'toggled-on' ); 1122 submenu.classList.remove( 'astra-megamenu-focus' ); 1123 const toggle = submenu.closest( '.menu-item-has-children' ).querySelector( '.ast-header-navigation-arrow' ); 1124 if ( toggle ) { 1125 toggle.setAttribute( 'aria-expanded', 'false' ); 1126 } 1127 1128 /** 1129 * If there's a bubbling end, set recursive to true. This recursive closing 1130 * the submenu upwards will end till this bubbleEnd element referenced at line 1168 1131 **/ 1132 if ( bubblingEnd ) { 1133 recursive = true; 1134 } 1135 1136 if( ! recursive ) { 1137 return; 1138 } 1139 1140 const parentSubmenu = submenu.parentElement.closest( '.sub-menu' ); 1141 1142 // If there's a parent submenu, close it and continue closing upwards. 1143 if( null !== parentSubmenu && submenu !== bubblingEnd ) { 1144 recursiveMenuCloseOnblur( parentSubmenu, true, bubblingEnd ); 1145 } 1146 } 1147 1148 function closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth) { 1149 if (siteNavigationSubMenu) { 1150 siteNavigationSubMenu.forEach(element => { 1151 element.classList.remove('astra-megamenu-focus'); 1152 element.classList.remove('toggled-on'); 1153 }); 1154 } 1155 1156 if (menuLi) { 1157 menuLi.forEach(element => { 1158 element.classList.remove('ast-menu-hover'); 1159 }); 1160 } 1161 1162 if (megaMenuFullWidth) { 1163 megaMenuFullWidth.forEach(element => { 1164 element.classList.remove('astra-megamenu-wrapper-focus') 1165 }); 1166 } 1167 1168 1169 if (dropdownToggleLinks) { 1170 dropdownToggleLinks.forEach(element => { 1171 element.setAttribute('aria-expanded', 'false'); 1172 }); 1173 } 1174 } 1175
1176 /** 1177 * Close the Toggle Menu on Click on hash (#) link. 1178 * 1179 * @since 1.3.2 1180 * @return void 1181 */ 1182 function toggleClose( ) 1183 { 1184 var self = this || '', 1185 hash = '#'; 1186 1187 if( self && ! self.classList.contains('astra-search-icon') && null === self.closest('.ast-builder-menu') ) { 1188 var link = String( self ); 1189 if( link.indexOf( hash ) !== -1 ) { 1190 var link_parent = self.parentNode; 1191 if ( body.classList.contains('ast-header-break-point') ) { 1192 if( ! ( document.querySelector('header.site-header').classList.contains('ast-builder-menu-toggle-link') && link_parent.classList.contains('menu-item-has-children') ) ) { 1193 /* Close Builder Header Menu */ 1194 var builder_header_menu_toggle = document.querySelector( '.main-header-menu-toggle' ); 1195 builder_header_menu_toggle.classList.remove( 'toggled' ); 1196 1197 var main_header_bar_navigation = document.querySelector( '.main-header-bar-navigation' ); 1198 main_header_bar_navigation.classList.remove( 'toggle-on' ); 1199 1200 main_header_bar_navigation.style.display = 'none'; 1201 1202 astraTriggerEvent( document.querySelector('body'), 'astraMenuHashLinkClicked' ); 1203 } 1204 1205 } else { 1206 while ( -1 === self.className.indexOf( 'nav-menu' ) ) { 1207 // On li elements toggle the class .focus. 1208 if ( 'li' === self.tagName.toLowerCase() ) { 1209 if ( -1 !== self.className.indexOf( 'focus' ) ) { 1210 self.className = self.className.replace( ' focus', '' ); 1211 } 1212 } 1213 self = self.parentElement; 1214 } 1215 } 1216 } 1217 } 1218 } 1219 1220 /** 1221 * Sets or removes .focus class on an element on focus. 1222 */ 1223 function toggleFocus() { 1224 var self = this; 1225 // Move up through the ancestors of the current link until we hit .nav-menu. 1226 while ( -1 === self.className.indexOf( 'navigation-accessibility' ) ) { 1227 // On li elements toggle the class .focus. 1228 if ( 'li' === self.tagName.toLowerCase() ) { 1229 self.classList.toggle('focus'); 1230 } 1231 self = self.parentElement; 1232 } 1233 } 1234 1235 if( ! astra.is_header_footer_builder_active ) { 1236 1237 /* Add class if mouse clicked and remove if tab pressed */ 1238 if ( 'querySelector' in document && 'addEventListener' in window ) { 1239 body.addEventListener( 'mousedown', function() { 1240 body.classList.add( 'ast-mouse-clicked' ); 1241 } ); 1242 1243 body.addEventListener( 'keydown', function() { 1244 body.classList.remove( 'ast-mouse-clicked' ); 1245 } ); 1246 } 1247 } 1248 1249 /** 1250 * Scroll to specific hash link. 1251 * 1252 * @since x.x.x 1253 */ 1254 if ( astra.is_scroll_to_id ) { 1255 // Calculate the offset top of an element, accounting for nested elements. 1256 const getOffsetTop = (element) => { 1257 let offsetTop = 0; 1258 while (element) { 1259 offsetTop += element.offsetTop; 1260 element = element.offsetParent; 1261 } 1262 return offsetTop; 1263 } 1264 1265 const scrollToIDHandler = ( e, hash = null ) => { 1266 1267 let offset = 0; 1268 const siteHeader = document.querySelector('.site-header'); 1269 1270 if (siteHeader) { 1271 1272 // Check and add offset to scroll top if header is sticky. 1273 const stickyHeaders = siteHeader.querySelectorAll( 1274 'div[data-stick-support]' 1275 ); 1276 1277 if ( stickyHeaders.length > 0 ) { 1278 stickyHeaders.forEach( ( header ) => ( offset += header.clientHeight ) ); 1279 } else if ( typeof astraAddon !== 'undefined' && ! ( Number( astraAddon.sticky_hide_on_scroll ) && ! document?.querySelector( '.ast-header-sticked' ) ) ) { 1280 const fixedHeader = document.querySelector( '#ast-fixed-header' ); 1281 if ( fixedHeader ) { 1282 offset = fixedHeader?.clientHeight; 1283 if ( Number( astraAddon?.header_main_shrink ) ) { 1284 const headers = fixedHeader?.querySelectorAll( 1285 '.ast-above-header-wrap, .ast-below-header-wrap' 1286 ); 1287 headers?.forEach( () => ( offset -= 10 ) ); 1288 } 1289 } 1290 } 1291 1292 const href = hash ? hash : e.target?.closest( 'a' ).hash; 1293 if (href) { 1294 const scrollId = document.querySelector(href); 1295 if (scrollId) { 1296 const elementOffsetTop = getOffsetTop( scrollId ); 1297 if ( typeof astraAddon !== 'undefined' && Number( astraAddon.sticky_hide_on_scroll ) && window?.scrollY < elementOffsetTop ) { 1298 offset = 0; 1299 } 1300 1301 const scrollOffsetTop = elementOffsetTop - offset; 1302 if( scrollOffsetTop ) { 1303 astraSmoothScroll( e, scrollOffsetTop ); 1304 } 1305 } 1306 } 1307 } 1308 } 1309 1310 let hashLinks = []; 1311 const links = document.querySelectorAll( 1312 'a[href*="#"]:not([href="#"]):not([href="#0"]):not([href*="uagb-tab"]):not(.uagb-toc-link__trigger):not(.skip-link):not(.nav-links a):not([href*="tab-"])' 1313 ); 1314 if (links) { 1315 for (const link of links) { 1316 if (link.href.split("#")[0] !== location.href.split("#")[0]) { 1317 // Store the hash 1318 hashLinks.push({ 1319 hash: link.hash, 1320 url: link.href.split("#")[0], 1321 }); 1322 } else if (link.hash !== "") { 1323 link.addEventListener("click", scrollToIDHandler); 1324 } 1325 } 1326 } 1327 1328 window.addEventListener('DOMContentLoaded', (event) => { 1329 for (let link of hashLinks) { 1330 if (window.location.href.split('#')[0] === link.url) { 1331 const siteHeader = document.querySelector('.site-header'); 1332 let offset = 0; 1333 1334 // Check and add offset to scroll top if header is sticky. 1335 const headerHeight = siteHeader.querySelectorAll('div[data-stick-support]'); 1336 if (headerHeight) { 1337 headerHeight.forEach(single => { 1338 offset += single.clientHeight; 1339 }); 1340 } 1341 1342 const scrollId = document.querySelector(link.hash); 1343 if (scrollId) { 1344 const scrollOffsetTop = getOffsetTop(scrollId) - offset; 1345 if (scrollOffsetTop) { 1346 astraSmoothScroll(event, scrollOffsetTop); 1347 } 1348 } 1349 } 1350 } 1351 1352 // If there is a hash in the URL when the page loads, scroll to that element after a short delay. 1353 if ( location.hash ) { 1354 setTimeout( () => scrollToIDHandler( new Event( 'click' ), location.hash ), 750 ); 1355 } 1356 }); 1357 } 1358 1359 /** 1360 * Scroll to top. 1361 * 1362 * @since x.x.x 1363 */ 1364 if ( astra.is_scroll_to_top ) { 1365 var masthead = document.querySelector( '#page header' ); 1366 var astScrollTop = document.getElementById( 'ast-scroll-top' ); 1367 1368 astScrollToTopHandler(masthead, astScrollTop); 1369 1370 window.addEventListener('scroll', function () { 1371 astScrollToTopHandler(masthead, astScrollTop); 1372 }); 1373 1374 astScrollTop.onclick = function(e){ 1375 astraSmoothScroll( e, 0 ); 1376 }; 1377 1378 astScrollTop.addEventListener( 'keydown' , function(e) { 1379 if ( e.key === 'Enter') { 1380 astraSmoothScroll( e, 0 ); 1381 } 1382 }); 1383 } 1384
1385 if ( astra?.is_dark_palette ) { 1386 document.documentElement.classList.add("astra-dark-mode-enable"); 1387 } else { 1388 document.documentElement.classList.remove("astra-dark-mode-enable"); 1389 } 1390 1391 /** 1392 * To remove the blank space when the store notice gets dismissed. 1393 * To adjust the height of the store notice when hanged over top. 1394 * 1395 * @since x.x.x 1396 */ 1397 window.addEventListener('DOMContentLoaded', (event) => { 1398 const isHangOverTopNotice = document.querySelector('.ast-woocommerce-store-notice-hanged'); 1399 const adjustBodyHeight = () => { 1400 const storeNotice = document.querySelector('.woocommerce-store-notice[data-position="hang-over-top"]'); 1401 document.body.style.paddingTop = `${storeNotice?.clientHeight || 0}px`; 1402 } 1403 1404 if (isHangOverTopNotice) { 1405 window.addEventListener('resize', adjustBodyHeight); 1406 setTimeout(() => adjustBodyHeight(), 0); 1407 } 1408 1409 document 1410 .querySelector('.woocommerce-store-notice__dismiss-link') 1411 ?.addEventListener('click', () => { 1412 if ( typeof wp === 'undefined' || ! wp?.customize ) { 1413 document.body.classList.remove('ast-woocommerce-store-notice-hanged'); 1414 window.removeEventListener('resize', adjustBodyHeight); 1415 document.body.style.paddingTop = 0; 1416 } 1417 }); 1418 }); 1419 1420})(); 1421 1422// Accessibility improvement for menu items. 1423document.addEventListener('DOMContentLoaded', function () { 1424 const submenuToggles = document.querySelectorAll('.menu-link .dropdown-menu-toggle'); 1425 1426 const menuItemsWithSubmenu = document.querySelectorAll('.menu-item-has-children > a'); 1427 1428 // Ensuring the submenu toggle action is handled with appropriate CSS, with cross browser compatibility for Enter key press. 1429 menuItemsWithSubmenu.forEach(item => { 1430 item.addEventListener('keydown', function(event) { 1431 if (event.key === 'Enter') { 1432 const submenu = item.nextElementSibling; 1433 if (submenu && submenu.classList.contains('sub-menu')) { 1434 submenu.classList.toggle('ast-visible'); 1435 const ariaExpanded = item.getAttribute('aria-expanded') === 'false' ? 'true' : 'false'; 1436 item.setAttribute('aria-expanded', ariaExpanded); 1437 } 1438 } 1439 }); 1440 }); 1441 1442 // Add event listeners for focus, blur, and keydown events. 1443 submenuToggles.forEach(toggle => { 1444 toggle.addEventListener('focus', () => updateAriaExpanded(toggle)); 1445 toggle.addEventListener('blur', () => updateAriaExpanded(toggle)); 1446 toggle.addEventListener('keydown', event => { 1447 if (event.key === 'Enter' || event.key === ' ') { 1448 event.preventDefault(); 1449 toggleAriaExpanded(toggle); 1450 } 1451 }); 1452 }); 1453 1454 // Add event listener for Escape key press to close all submenus. 1455 document.addEventListener('keydown', event => { 1456 if (event.key === 'Escape') { 1457 closeAllSubmenus(); 1458 } 1459 }); 1460 1461 /** 1462 * Updates the `aria-expanded` attribute based on submenu visibility. 1463 * @param {HTMLElement} toggle - The toggle element. 1464 */ 1465 function updateAriaExpanded(toggle) { 1466 const menuItemLink = toggle.closest('.menu-link'); 1467 const submenu = menuItemLink.nextElementSibling; 1468 const isSubmenuVisible = submenu.classList.contains('toggled-on'); 1469 menuItemLink.setAttribute('aria-expanded', isSubmenuVisible ? 'true' : 'false'); 1470 } 1471 1472 /** 1473 * Toggles the `aria-expanded` attribute for a given toggle element. 1474 * @param {HTMLElement} toggle - The toggle element. 1475 */ 1476 function toggleAriaExpanded(toggle) { 1477 const menuItemLink = toggle.closest('.menu-link'); 1478 const currentState = menuItemLink.getAttribute('aria-expanded'); 1479 menuItemLink.setAttribute('aria-expanded', currentState === 'true' ? 'false' : 'true'); 1480 } 1481 1482 /** 1483 * Closes all submenus by updating the `aria-expanded` attribute. 1484 */ 1485 function closeAllSubmenus() { 1486 submenuToggles.forEach(toggle => updateAriaExpanded(toggle)); 1487 } 1488 1489 // This event listener is triggered when the device orientation changes, and it dispatches a 'resize' event to ensure layout adjustments are made. 1490 window.addEventListener( 'orientationchange', () => { 1491 setTimeout( () => window.dispatchEvent( new Event( 'resize' ) ), 50 ); 1492 } ); 1493}); 1494 1495// Accessibility improvement for product card quick view and add to cart buttons. 1496document.addEventListener('DOMContentLoaded', () => { 1497 const thumbnailWraps = document.querySelectorAll('.astra-shop-thumbn
1497ail-wrap'); 1498 1499 thumbnailWraps.forEach(wrap => { 1500 const focusableElements = wrap.querySelectorAll('a, span'); 1501 1502 focusableElements.forEach(el => { 1503 el.addEventListener('focus', () => { 1504 wrap.querySelectorAll('.ast-on-card-button, .ast-quick-view-trigger').forEach(btn => { 1505 btn.style.opacity = '1'; 1506 btn.style.visibility = 'visible'; 1507 btn.style.borderStyle = 'none'; 1508 }); 1509 }); 1510 1511 el.addEventListener('blur', () => { 1512 // Added Check to check if child elements are still focused. 1513 const isAnyFocused = Array.from(focusableElements).some(child => child === document.activeElement); 1514 if (!isAnyFocused) { 1515 wrap.querySelectorAll('.ast-on-card-button, .ast-quick-view-trigger').forEach(btn => { 1516 btn.style.opacity = ''; 1517 btn.style.visibility = ''; 1518 }); 1519 } 1520 }); 1521 }); 1522 }); 1523});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.