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 desktop dropdown. 478 if ( desktopDropdownContent ) { 479 var desktopLinks = desktopDropdownContent.getElementsByTagName( 'a' ); 480 for ( link = 0, len = desktopLinks.length; link < len; link++ ) { 481 // Check if the link is not inside the tabs container. 482 const isNotInsideTabsContainer = desktopLinks[ link ].closest( '.wp-block-uagb-tabs' ) === null; 483 484 if ( 485 null !== desktopLinks[ link ].getAttribute( 'href' ) && 486 ( desktopLinks[ link ].getAttribute( 'href' ).startsWith( '#' ) || 487 -1 !== desktopLinks[ link ].getAttribute( 'href' ).search( '#' ) ) && 488 ( ! desktopLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) || 489 ( desktopLinks[ link ].parentElement.classList.contains( 'menu-item-has-children' ) && 490 document.querySelector( 'header.site-header' ).classList.contains( 'ast-builder-menu-toggle-icon' ) ) ) && 491 isNotInsideTabsContainer 492 ) { 493 desktopLinks[ link ].addEventListener( 'click', triggerToggleClose, true ); 494 desktopLinks[ link ].headerType = 'dropdown'; 495 } 496 } 497 } 498 499 for ( var item = 0; item < popupTriggerMobile.length; item++ ) { 500 popupTriggerMobile[ item ].removeEventListener( 'click', popupTriggerClick, false ); 501 popupTriggerMobile[ item ].removeEventListener( 'click', astraNavMenuToggle ); 502 popupTriggerMobile[ item ].addEventListener( 'click', astraNavMenuToggle, false ); 503 popupTriggerMobile[ item ].trigger_type = 'mobile'; 504 } 505 for ( var item = 0; item < popupTriggerDesktop.length; item++ ) { 506 popupTriggerDesktop[ item ].removeEventListener( 'click', popupTriggerClick, false ); 507 popupTriggerDesktop[ item ].removeEventListener( 'click', astraNavMenuToggle ); 508 popupTriggerDesktop[ item ].addEventListener( 'click', astraNavMenuToggle, false ); 509 popupTriggerDesktop[ item ].trigger_type = 'desktop'; 510 } 511 512 AstraToggleSetup(); 513 } 514 515 } 516 517 function triggerToggleClose( event ) { 518 519 var headerType = event.currentTarget.headerType; 520 521 switch( headerType ) { 522 523 case 'dropdown': 524 525 var popupTrigger = document.querySelectorAll( '.menu-toggle.toggled' ); 526 527 for ( var item = 0; item < popupTrigger.length; item++ ) { 528 529 popupTrigger[item].click(); 530 } 531 break; 532 case 'off-canvas': 533 534 var popupClose = document.getElementById( 'menu-toggle-close' ); 535 536 popupClose.click(); 537 break; 538 default: 539 break; 540 } 541 } 542 543 window.addEventListener( 'load', function() { 544 init(); 545 } ); 546 document.addEventListener( 'astLayoutWidthChanged', function() { 547 init(); 548 } ); 549 550 document.addEventListener( 'astPartialContentRendered', function() { 551 552 menu_toggle_all = document.querySelectorAll( '.main-header-menu-toggle' ); 553 554 body.classList.remove("ast-main-header-nav-open"); 555 556 document.addEventListener( 'astMobileHeaderTypeChange', updateHeaderType, false ); 557 558 init(); 559 560 } ); 561 562 var mobile_width = ( null !== navigator.userAgent.match(/Android/i) && 'Android' === navigator.userAgent.match(/Android/i)[0] ) ? window.visualVie
562wport.width : window.innerWidth; 563 564 function AstraHandleResizeEvent() { 565 566 var menu_offcanvas_close = document.getElementById('menu-toggle-close'); 567 var menu_dropdown_close = document.querySelector('.menu-toggle.toggled'); 568 var desktop_header_content = document.querySelector('#masthead > #ast-desktop-header .ast-desktop-header-content'); 569 var elementor_editor = document.querySelector('.elementor-editor-active'); 570 571 if ( desktop_header_content ) { 572 desktop_header_content.style.display = 'none'; 573 } 574 var mobileResizeWidth = ( null !== navigator.userAgent.match(/Android/i) && 'Android' === navigator.userAgent.match(/Android/i)[0] ) ? window.visualViewport.width : window.innerWidth; 575 576 if ( mobileResizeWidth !== mobile_width ) { 577 if ( menu_dropdown_close && null === elementor_editor ) { 578 menu_dropdown_close.click(); 579 } 580 document.body.classList.remove( 'ast-main-header-nav-open', 'ast-popup-nav-open' ); 581 582 if( menu_offcanvas_close && null == elementor_editor ) { 583 menu_offcanvas_close.click(); 584 } 585 } 586 587 updateHeaderBreakPoint(); 588 589 AstraToggleSetup(); 590 591 } 592 593 window.addEventListener('resize', function(){ 594 // Skip resize event when keyboard display event triggers on devices. 595 if( 'INPUT' !== document.activeElement.tagName ) { 596 AstraHandleResizeEvent(); 597 } 598 } ); 599 600 document.addEventListener('DOMContentLoaded', function () { 601 AstraToggleSetup(); 602 /** 603 * Navigation Keyboard Navigation. 604 */ 605 var containerButton; 606 if ( body.classList.contains('ast-header-break-point') ) { 607 containerButton = document.getElementById( 'ast-mobile-header' ); 608 } else { 609 containerButton = document.getElementById( 'ast-desktop-header' ); 610 } 611 612 if( null !== containerButton ) { 613 var containerMenu = containerButton.querySelector( '.navigation-accessibility' ); 614 navigation_accessibility( containerMenu, containerButton ); 615 } 616 }); 617 618 var get_window_width = function () { 619 620 return window.innerWidth; 621 } 622 623 /* Add break point Class and related trigger */ 624 var updateHeaderBreakPoint = function () { 625 626 var ww = get_window_width(); 627 628 var break_point = astra.break_point; 629 630 /** 631 * Use matchMedia to evaluate the breakpoint using the same CSS engine that 632 * evaluates media queries. This guarantees JS and CSS always agree on which 633 * header should be visible, eliminating any sub-pixel or scrollbar-width 634 * mismatch between window.innerWidth and the actual CSS viewport width. 635 * 636 * The 0.99 offset mirrors the max-width: (break_point + 0.99)px rule used 637 * in the PHP dynamic CSS, so the transition point is identical in both. 638 * 639 * The 0 === ww guard handles a Chrome edge case where innerWidth returns 0 640 * when opening a URL via "Open in New Tab" — force desktop mode in that case. 641 */ 642 var isMobile = window.matchMedia( '(max-width: ' + ( parseFloat( break_point ) + 0.99 ) + 'px)' ).matches; 643 644 if ( ! isMobile || 0 === ww ) { 645 //remove menu toggled class. 646 if ( menu_toggle_all.length > 0 ) { 647 648 for (var i = 0; i < menu_toggle_all.length; i++) { 649 650 if( null !== menu_toggle_all[i] ) { 651 menu_toggle_all[i].classList.remove('toggled'); 652 } 653 } 654 } 655 body.classList.remove("ast-header-break-point"); 656 body.classList.add("ast-desktop"); 657 astraTriggerEvent(body, "astra-header-responsive-enabled"); 658 659 } else { 660 661 body.classList.add("ast-header-break-point"); 662 body.classList.remove("ast-desktop"); 663 astraTriggerEvent(body, "astra-header-responsive-disabled") 664 } 665 } 666 667 updateHeaderBreakPoint(); 668 body.classList.add( 'ast-header-loaded' ); 669 670 AstraToggleSubMenu = function( event ) { 671 672 event.preventDefault(); 673 674 var parent_li = this.parentNode; 675 676 // In Link mode, stop the click from bubbling when toggling a parent menu 677 // item's submenu. Without this, the click propagates to document-level 678 // handlers that close the entire dropdown (desktop and mobile). 679 if ( parent_li.classList.contains( 'menu-item-has-children' ) && 680 document.querySelector( 'header.site-header' ).classList.contains( 'ast-builder-menu-toggle-link' ) ) { 681 event.stopPropagation(); 682 } 683 684 if ('false' === event.target.getAttribute('aria-expanded') || ! event.target.getAttribute('aria-expanded')) { 685 event.target.setAttribute('aria-expanded', 'true'); 686 } else { 687 event.target.setAttribute('aria-expanded', 'false'); 688 } 689 690 if ( parent_li.classList.contains('ast-submenu-expanded') && document.querySelector('header.site-header').classList.contains('ast-builder
690-menu-toggle-link') ) { 691 692 if (!this.classList.contains('ast-menu-toggle')) { 693 694 var link = parent_li.querySelector('a').getAttribute('href'); 695 if ( '' !== link && '#' !== link) { 696 window.location = link; 697 } 698 } 699 } 700 701 var parent_li_child = parent_li.querySelectorAll('.menu-item-has-children'); 702 for (var j = 0; j < parent_li_child.length; j++) { 703 704 parent_li_child[j].classList.remove('ast-submenu-expanded'); 705 var parent_li_child_sub_menu = parent_li_child[j].querySelector('.sub-menu, .children'); 706 if( null !== parent_li_child_sub_menu ) { 707 parent_li_child_sub_menu.style.display = 'none'; 708 } 709 } 710 711 var parent_li_sibling = parent_li.parentNode.querySelectorAll('.menu-item-has-children'); 712 for (var j = 0; j < parent_li_sibling.length; j++) { 713 714 if (parent_li_sibling[j] != parent_li) { 715 716 parent_li_sibling[j].classList.remove('ast-submenu-expanded'); 717 var all_sub_menu = parent_li_sibling[j].querySelectorAll('.sub-menu'); 718 for (var k = 0; k < all_sub_menu.length; k++) { 719 all_sub_menu[k].style.display = 'none'; 720 } 721 } 722 } 723 724 if (parent_li.classList.contains('menu-item-has-children') ) { 725 astraToggleClass(parent_li, 'ast-submenu-expanded'); 726 if (parent_li.classList.contains('ast-submenu-expanded')) { 727 parent_li.querySelector('.sub-menu').style.display = 'block'; 728 } else { 729 parent_li.querySelector('.sub-menu').style.display = 'none'; 730 } 731 } 732 }; 733 734 AstraToggleSetup = function () { 735 736 if( typeof astraAddon != 'undefined' && typeof astraToggleSetupPro === "function" ) { 737 astraToggleSetupPro( mobileHeaderType, body, menu_click_listeners_nav ); 738 } else { 739 var flag = false; 740 var menuToggleAllLength; 741 if ( 'off-canvas' === mobileHeaderType || 'full-width' === mobileHeaderType ) { 742 // 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. 743 var __main_header_all = document.querySelectorAll( '#ast-mobile-popup, #ast-mobile-header' ); 744 var menu_toggle_all = document.querySelectorAll('#ast-mobile-header .main-header-menu-toggle'); 745 746 menuToggleAllLength = menu_toggle_all.length; 747 } else { 748 var __main_header_all = document.querySelectorAll( '#ast-mobile-header' ), 749 menu_toggle_all = document.querySelectorAll('#ast-mobile-header .main-header-menu-toggle'); 750 menuToggleAllLength = menu_toggle_all.length; 751 flag = menuToggleAllLength > 0 ? false : true; 752 753 menuToggleAllLength = flag ? 1 : menuToggleAllLength; 754 755 } 756 757 if ( menuToggleAllLength > 0 || flag ) { 758 759 for (var i = 0; i < menuToggleAllLength; i++) { 760 761 if ( ! flag ) { 762 763 menu_toggle_all[i].setAttribute('data-index', i); 764 765 if ( ! menu_click_listeners_nav[i] ) { 766 menu_click_listeners_nav[i] = menu_toggle_all[i]; 767 menu_toggle_all[i].removeEventListener('click', astraNavMenuToggle); 768 menu_toggle_all[i].addEventListener('click', astraNavMenuToggle, false); 769 } 770 } 771 772 if ('undefined' !== typeof __main_header_all[i]) { 773 774 // To handle the comma seprated selector added above we need this loop. 775 for( var mainHeaderCount =0; mainHeaderCount < __main_header_all.length; mainHeaderCount++ ){ 776 777 if (document.querySelector('header.site-header').classList.contains('ast-builder-menu-toggle-link')) { 778 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'); 779 } else { 780 var astra_menu_toggle = __main_header_all[mainHeaderCount].querySelectorAll('ul.main-header-menu .ast-menu-toggle'); 781 } 782 // Add Eventlisteners for Submenu. 783 if (astra_menu_toggle.length > 0) { 784 785 for (var j = 0; j < astra_menu_toggle.length; j++) { 786 astra_menu_toggle[j].removeEventListener('click', AstraToggleSubMenu); 787 astra_menu_toggle[j].addEventListener('click', AstraToggleSubMenu, false); 788 } 789 } 790 } 791 } 792 } 793 } 794 } 795 }; 796 797 astraNavMenuToggle = function ( event ) { 798 799 if( typeof astraAddon != 'undefined' ) { 800 astraNavMenuTogglePro( event, body, mobileHeaderType, this ); 801 } else { 802 803 event.preventDefault(); 804 var __main_header_all = document.querySelectorAll('#masthead > #ast-mobile-header .main-header-bar-navigation'); 805 menu_toggle_all = document.querySelectorAll( '#masthead > #ast-mobile-header .main-header-menu-toggle' ) 806 var event_index = '0'; 807 808 if ( null !== this.closest( '#ast-fixed-header' ) ) { 809 810 __main_header_all = document.querySelectorAll('#ast-fixed-header > #ast-mobile-header .main-header-bar-navigation'); 811 menu_toggle_all = document.querySelectorAll( '#ast-fixed-header .main-header-menu-toggle' ) 812 813 event_index = '0'; 814 } 815 816 if ('undefined' === typeof __main_header_all[event_index]) { 817 return false;
818 } 819 var menuHasChildren = __main_header_all[event_index].querySelectorAll('.menu-item-has-children'); 820 for (var i = 0; i < menuHasChildren.length; i++) { 821 menuHasChildren[i].classList.remove('ast-submenu-expanded'); 822 var menuHasChildrenSubMenu = menuHasChildren[i].querySelectorAll('.sub-menu'); 823 for (var j = 0; j < menuHasChildrenSubMenu.length; j++) { 824 menuHasChildrenSubMenu[j].style.display = 'none'; 825 } 826 } 827 828 var menu_class = this.getAttribute('class') || ''; 829 830 if ( menu_class.indexOf('main-header-menu-toggle') !== -1 ) { 831 astraToggleClass(__main_header_all[event_index], 'toggle-on'); 832 astraToggleClass(menu_toggle_all[event_index], 'toggled'); 833 if (__main_header_all[event_index].classList.contains('toggle-on')) { 834 __main_header_all[event_index].style.display = 'block'; 835 body.classList.add("ast-main-header-nav-open"); 836 } else { 837 __main_header_all[event_index].style.display = ''; 838 body.classList.remove("ast-main-header-nav-open"); 839 } 840 } 841 } 842 }; 843 844 body.addEventListener("astra-header-responsive-enabled", function () { 845 846 var __main_header_all = document.querySelectorAll('.main-header-bar-navigation'); 847 848 if (__main_header_all.length > 0) { 849 850 for (var i = 0; i < __main_header_all.length; i++) { 851 if (null != __main_header_all[i]) { 852 __main_header_all[i].classList.remove('toggle-on'); 853 __main_header_all[i].style.display = ''; 854 } 855 856 var sub_menu = __main_header_all[i].getElementsByClassName('sub-menu'); 857 for (var j = 0; j < sub_menu.length; j++) { 858 sub_menu[j].style.display = ''; 859 } 860 var child_menu = __main_header_all[i].getElementsByClassName('children'); 861 for (var k = 0; k < child_menu.length; k++) { 862 child_menu[k].style.display = ''; 863 } 864 865 var searchIcons = __main_header_all[i].getElementsByClassName('ast-search-menu-icon'); 866 for (var l = 0; l < searchIcons.length; l++) { 867 searchIcons[l].classList.remove('ast-dropdown-active'); 868 searchIcons[l].style.display = ''; 869 } 870 } 871 } 872 }, false); 873 874 875 /* Search Script */ 876 var SearchIcons = document.getElementsByClassName( 'astra-search-icon' ); 877 for (var i = 0; i < SearchIcons.length; i++) { 878 879 SearchIcons[i].onclick = function(event) { 880 if ( this.classList.contains( 'slide-search' ) ) { 881 event.preventDefault(); 882 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 883 if ( ! sibling.classList.contains( 'ast-dropdown-active' ) ) { 884 sibling.classList.add( 'ast-dropdown-active' ); 885 sibling.querySelector( '.search-field' ).setAttribute('autocomplete','off'); 886 setTimeout(function() { 887 sibling.querySelector( '.search-field' ).focus(); 888 },200); 889 } else { 890 var searchTerm = sibling.querySelector( '.search-field' ).value || ''; 891 if( '' !== searchTerm ) { 892 sibling.querySelector( '.search-form' ).submit(); 893 } 894 sibling.classList.remove( 'ast-dropdown-active' ); 895 } 896 } 897 } 898 } 899 var SearchInputs = document.querySelectorAll( '.search-field' ); 900 SearchInputs.forEach(input => { 901 input.addEventListener('focus', function (e) { 902 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 903 if ( sibling ) { 904 astraToggleClass( sibling, 'ast-dropdown-active' ); 905 } 906 }); 907 input.addEventListener('blur', function (e) { 908 var sibling = this.parentNode.parentNode.parentNode.querySelector( '.ast-search-menu-icon' ); 909 if ( sibling ) { 910 sibling.classList.remove( 'ast-dropdown-active' ); 911 astraToggleClass( sibling, 'ast-dropdown-active' ); 912 } 913 }); 914 }); 915 916 /* Hide Dropdown on body click*/ 917 body.onclick = function( event ) { 918 if ( typeof event.target.classList !== 'undefined' ) { 919 if ( ! event.target.classList.contains( 'ast-search-menu-icon' ) && ! event.target.closest( '.ast-search-menu-icon' ) && ! event.target.closest( '.ast-search-icon' ) ) {
920 var dropdownSearchWrap = document.getElementsByClassName( 'ast-search-menu-icon' ); 921 for (var i = 0; i < dropdownSearchWrap.length; i++) { 922 dropdownSearchWrap[i].classList.remove( 'ast-dropdown-active' ); 923 } 924 } 925 } 926 } 927 928 /** 929 * Navigation Keyboard Navigation. 930 */ 931 function navigation_accessibility(containerMenu, containerButton) { 932 if (!containerMenu || !containerButton) { 933 return; 934 } 935 var button = containerButton.getElementsByTagName('button')[0] || containerButton.getElementsByTagName('a')[0]; 936 if (!button || (button.classList.contains('astra-search-icon'))) { 937 return; 938 } 939 var menu = containerMenu.getElementsByTagName('ul')[0]; 940 941 // Hide menu toggle button if menu is empty and return early. 942 if (!menu) { 943 if (!button.classList.contains('custom-logo-link')) { 944 button.style.display = 'none'; 945 } 946 return; 947 } 948 949 if (!menu.className.includes('nav-menu')) { 950 menu.className += ' nav-menu'; 951 } 952 953 document.addEventListener('DOMContentLoaded', function () { 954 if ('off-canvas' === mobileHeaderType) { 955 var popupClose = document.getElementById('menu-toggle-close'); 956 if (popupClose) { 957 popupClose.onclick = function () { 958 var toggled = containerMenu.className.includes('toggled'); 959 containerMenu.className = toggled ? containerMenu.className.replace(' toggled', '') : containerMenu.className + ' toggled'; 960 button.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 961 menu.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 962 }; 963 } 964 } 965 }); 966 967 button.onclick = function () { 968 var toggled = containerMenu.className.includes('toggled'); 969 containerMenu.className = toggled ? containerMenu.className.replace(' toggled', '') : containerMenu.className + ' toggled'; 970 button.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 971 menu.setAttribute('aria-expanded', toggled ? 'false' : 'true'); 972 }; 973 974 if (!astra.is_header_footer_builder_active) { 975 976 // Get all the link elements within the menu. 977 var links = menu.getElementsByTagName('a'); 978 var subMenus = menu.getElementsByTagName('ul'); 979 980 // Set menu items with submenus to aria-haspopup="true". 981 for (var i = 0, len = subMenus.length; i < len; i++) { 982 subMenus[i].parentNode.setAttribute('aria-haspopup', 'true'); 983 } 984 985 // Each time a menu link is focused or blurred, toggle focus. 986 for (var i = 0, len = links.length; i < len; i++) { 987 links[i].addEventListener('focus', toggleFocus, true); 988 links[i].addEventListener('blur', toggleFocus, true); 989 links[i].addEventListener('click', toggleClose, true); 990 } 991 } 992 993 if (astra.is_header_footer_builder_active) { 994 tabNavigation(); 995 } 996 } 997 998 // Tab navigation for accessibility. 999 function tabNavigation() { 1000 const dropdownToggleLinks = document.querySelectorAll('nav.site-navigation .menu-item-has-children > a .ast-header-navigation-arrow'); 1001 const siteNavigationSubMenu = document.querySelectorAll('nav.site-navigation .sub-menu'); 1002 const menuLi = document.querySelectorAll('nav.site-navigation .menu-item-has-children'); 1003 const megaMenuFullWidth = document.querySelectorAll('.astra-full-megamenu-wrapper'); 1004 1005 if (dropdownToggleLinks) { 1006 dropdownToggleLinks.forEach(element => { 1007 element.addEventListener('keydown', function (e) { 1008 if ('Enter' === e.key || ' ' === e.key) { 1009 // Check if the user is on a mobile device and prevent default and stop propagation if true. 1010 if ( /Mobi|Android|iPad|iPhone/i.test( navigator.userAgent ) ) { 1011 e.preventDefault(); 1012 e.stopPropagation(); 1013 } 1014 1015 const closestLi = e.target.closest('li'); 1016 const subMenu = closestLi.querySelector('.sub-menu'); 1017 const isMegaMenu = subMenu && subMenu.classList.contains('astra-megamenu'); 1018 1019 setTimeout(() => { 1020 if (!isMegaMenu) { 1021 subMenu.classList.toggle('toggled-on'); 1022 closestLi.classList.toggle('ast-menu-hover'); 1023 } else { 1024 const fullMegaMenuWrapper = closestLi.querySelector('.astra-full-megamenu-wrapper'); 1025 if (subMenu) subMenu.classList.toggle('astra-megamenu-focus'); 1026 if (fullMegaMenuWrapper) fullMegaMenuWrapper.classList.toggle('astra-megamenu-wrapper-focus'); 1027 closestLi.classList.toggle('ast-menu-hover'); 1028 } 1029 1030 const ariaExpanded = e.target.getAttribute('aria-expanded'); 1031 e.target.setAttribute('aria-expanded', ariaExpanded === 'false' || !ariaExpanded ? 'true' : 'false'); 1032 }, 10); 1033 } 1034 }); 1035 1036 /** 1037 * Click cannot reliably report the input type - Firefox omits 1038 * pointerType - so record it per arrow here. 1039 */ 1040 element.addEventListener('pointerdown', function (e) { 1041 e.currentTarget.dataset.astPointerType = e.pointerType || 'mouse'; 1042 }, false); 1043 1044 /** 1045 * The arrow sits inside the parent <a>, so on touch the tap followed 1046 * the link and the submenu never opened. Touch reports no hover. 1047 */ 1048 element.addEventListener('click', function (e) { 1049 const arrow = e.currentTarget; 1050 1051 // Mouse and pen report hover, which already opens the submenu. 1052 if ('touch' !== arrow.dataset.astPointerType) { 1053 return; 1054 } 1055 1056 // Below the breakpoint the mobile menu has its own toggle. 1057 if (!body.classList.contains('ast-desktop')) { 1058 return; 1059 } 1060 1061 const closestLi = arrow.closest('li'); 1062 const subMenu = closestLi && closestLi.querySelector('.sub-menu'); 1063 1064 if (!subMenu) { 1065 return; 1066 } 1067 1068 e.preventDefault(); 1069 1070 // Or the document listener below closes it in the same tick. 1071 e.stopPropagation(); 1072 1073 // Read before closing, which resets aria-expanded on every arrow. 1074 const wasOpen = 'true' === arrow.getAttribute('aria-expanded'); 1075 1076 // Mouse and keyboard only ever leave one submenu open, so collapse 1077 // the others here too. 1078 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1079 1080 if (!wasOpen) { 1081 subMenu.classList.add('toggled-on'); 1082 closestLi.classList.add('ast-menu-hover'); 1083 arrow.setAttribute('aria-expanded', 'true'); 1084 } 1085 }, false); 1086 }); 1087 1088 if (siteNavigationSubMenu || menuLi) { 1089 document.addEventListener('click', function (e) { 1090 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1091 }, false); 1092 1093 document.addEventListener('keydown', function (e) { 1094 if ('Escape' === e.key) { 1095 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1096 } 1097 }, false); 1098 } 1099 } 1100 1101 const allParentMenu = document.querySelectorAll('nav.site-navigation .ast-nav-menu > .menu-item-has-children > a .ast-header-navigation-arrow'); 1102 1103 if (allParentMenu) { 1104 allParentMenu.forEach(element => { 1105 element.addEventListener('keydown', function (e) { 1106 if (!e.target.closest('li').classList.contains('ast-menu-hover') && 'Enter' === e.key) { 1107 closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth); 1108 } 1109 }, false); 1110 }); 1111 } 1112 1113 const desktopMenu = document.querySelectorAll( '#ast-desktop-header .ast-builder
1113-layout-element.ast-builder-menu' ); 1114 desktopMenu.forEach( menu => { 1115 const desktopMenuItems = menu.querySelectorAll( '.main-header-menu .menu-item > a' ); 1116 desktopMenuItems.forEach( ( item ) => { 1117 item.addEventListener( 'focusout', function( e ) { 1118 const nextFocus = e.relatedTarget; 1119 const nextFocusMenuItem = nextFocus ? nextFocus.closest( '.menu-item' ) : null; 1120 const currentFocus = e.target; 1121 const currentMenuItem = currentFocus.closest( '.menu-item' ); 1122 const subMenuOpened = currentMenuItem.classList.contains( 'ast-menu-hover' ); 1123 const subMenu = currentMenuItem.querySelector( '.sub-menu' ); 1124 const wrapperSubmenu = currentMenuItem.closest('.sub-menu') 1125 const parentMenuItem = currentMenuItem.closest('.sub-menu')?.closest( '.menu-item-has-children' ); 1126 const childMenuItem = currentMenuItem.querySelector( '.menu-item' ); 1127 1128 1129 // If the next focus is the same menu item or a child menu item, don't close the submenu. 1130 if ( 1131 currentMenuItem == nextFocusMenuItem || 1132 ( childMenuItem && childMenuItem == nextFocusMenuItem ) 1133 ) { 1134 return; 1135 } 1136 1137 // If there's no next focus, close all submenus. 1138 if( nextFocusMenuItem == null ) { 1139 if ( wrapperSubmenu ) 1140 recursiveMenuCloseOnblur( wrapperSubmenu ); 1141 if ( subMenu ) 1142 recursiveMenuCloseOnblur( subMenu ); 1143 return; 1144 } 1145 1146 // If the next focus is the next or previous sibling, don't close all the submenu. 1147 if ( 1148 currentMenuItem.nextElementSibling == nextFocusMenuItem || 1149 currentMenuItem.previousElementSibling == nextFocusMenuItem 1150 ) { 1151 // If the submenu is opened, close it and remove the 'ast-menu-hover' class. 1152 if( subMenuOpened ) { 1153 recursiveMenuCloseOnblur( subMenu, false ); 1154 currentMenuItem.classList.remove( 'ast-menu-hover' ); 1155 } 1156 return; 1157 } 1158 1159 // If the next focus is the parent menu item, close the submenu till the inner child menu item submenu 1160 if ( parentMenuItem && parentMenuItem == nextFocusMenuItem ) { 1161 childSubMenu = currentMenuItem.querySelector( '.sub-menu' ); 1162 recursiveMenuCloseOnblur( childSubMenu, false ); 1163 return; 1164 } 1165 1166 // Here we are setting a depth level point while traversing from lower to upper submenu parents. 1167 // The next focus is the next sibling of any of the parent elements in the tree, then close submenus till that level. 1168 let tempParent = parentMenuItem; 1169 let subMenuCloseEnd = null; 1170 while ( tempParent != null ) { 1171 if( tempParent.nextElementSibling == nextFocusMenuItem ) { 1172 subMenuCloseEnd = tempParent.querySelector( '.sub-menu' ); 1173 break; 1174 } 1175 tempParent = tempParent.closest('.sub-menu')?.closest( '.menu-item-has-children' ); 1176 } 1177 1178 // Closes all the menus. 1179 if( wrapperSubmenu ) 1180 recursiveMenuCloseOnblur( wrapperSubmenu, true, subMenuCloseEnd ); 1181 1182 }); 1183 }); 1184 }); 1185 } 1186 1187 // Recursively closes the submenu upwards 1188 function recursiveMenuCloseOnblur( submenu, recursive = true, bubblingEnd = null ) { 1189 /** 1190 * Close the submenu 1191 */ 1192 submenu.classList.remove( 'toggled-on' ); 1193 submenu.classList.remove( 'astra-megamenu-focus' ); 1194 const toggle = submenu.closest( '.menu-item-has-children' ).querySelector( '.ast-header-navigation-arrow' ); 1195 if ( toggle ) { 1196 toggle.setAttribute( 'aria-expanded', 'false' ); 1197 } 1198 1199 /** 1200 * If there's a bubbling end, set recursive to true. This recursive closing 1201 * the submenu upwards will end till this bubbleEnd element referenced at line 1168 1202 **/ 1203 if ( bubblingEnd ) { 1204 recursive = true; 1205 } 1206 1207 if( ! recursive ) { 1208 return; 1209 } 1210 1211 const parentSubmenu = submenu.parentElement.closest( '.sub-menu' ); 1212 1213 // If there's a parent submenu, close it and continue closing upwards. 1214 if( null !== parentSubmenu && submenu !== bubblingEnd ) { 1215 recursiveMenuCloseOnblur( parentSubmenu, true, bubblingEnd ); 1216 } 1217 } 1218 1219 function closeNavigationMenu(siteNavigationSubMenu, dropdownToggleLinks, menuLi, megaMenuFullWidth) { 1220 if (siteNavigationSubMenu) { 1221 siteNavigationSubMenu.forEach(element => { 1222 element.classList.remove('astra-megamenu-focus'); 1223 element.classList.remove('toggled-on'); 1224 }); 1225 } 1226 1227 if (menuLi) { 1228 menuLi.forEach(element => { 1229 element.classList.remove('ast-menu-hover'); 1230 }); 1231 } 1232 1233 if (megaMenuFullWidth) { 1234 megaMenuFullWidth.forEach(element => { 1235 element.classList.remove('astra-megamenu-wrapper-focus') 1236 }); 1237 } 1238 1239 1240 if (dropdownToggleLinks) { 1241 dropdownToggleLinks.forEach(element => { 1242 element.setAttribute('aria-expanded', 'false'); 1243 }); 1244 } 1245 } 1246
1247 /** 1248 * Close the Toggle Menu on Click on hash (#) link. 1249 * 1250 * @since 1.3.2 1251 * @return void 1252 */ 1253 function toggleClose( ) 1254 { 1255 var self = this || '', 1256 hash = '#'; 1257 1258 if( self && ! self.classList.contains('astra-search-icon') && null === self.closest('.ast-builder-menu') ) { 1259 var link = String( self ); 1260 if( link.indexOf( hash ) !== -1 ) { 1261 var link_parent = self.parentNode; 1262 if ( body.classList.contains('ast-header-break-point') ) { 1263 if( ! ( document.querySelector('header.site-header').classList.contains('ast-builder-menu-toggle-link') && link_parent.classList.contains('menu-item-has-children') ) ) { 1264 /* Close Builder Header Menu */ 1265 var builder_header_menu_toggle = document.querySelector( '.main-header-menu-toggle' ); 1266 builder_header_menu_toggle.classList.remove( 'toggled' ); 1267 1268 var main_header_bar_navigation = document.querySelector( '.main-header-bar-navigation' ); 1269 main_header_bar_navigation.classList.remove( 'toggle-on' ); 1270 1271 main_header_bar_navigation.style.display = 'none'; 1272 1273 astraTriggerEvent( document.querySelector('body'), 'astraMenuHashLinkClicked' ); 1274 } 1275 1276 } else { 1277 while ( -1 === self.className.indexOf( 'nav-menu' ) ) { 1278 // On li elements toggle the class .focus. 1279 if ( 'li' === self.tagName.toLowerCase() ) { 1280 if ( -1 !== self.className.indexOf( 'focus' ) ) { 1281 self.className = self.className.replace( ' focus', '' ); 1282 } 1283 } 1284 self = self.parentElement; 1285 } 1286 } 1287 } 1288 } 1289 } 1290 1291 /** 1292 * Sets or removes .focus class on an element on focus. 1293 */ 1294 function toggleFocus() { 1295 var self = this; 1296 // Move up through the ancestors of the current link until we hit .nav-menu. 1297 while ( -1 === self.className.indexOf( 'navigation-accessibility' ) ) { 1298 // On li elements toggle the class .focus. 1299 if ( 'li' === self.tagName.toLowerCase() ) { 1300 self.classList.toggle('focus'); 1301 } 1302 self = self.parentElement; 1303 } 1304 } 1305 1306 if( ! astra.is_header_footer_builder_active ) { 1307 1308 /* Add class if mouse clicked and remove if tab pressed */ 1309 if ( 'querySelector' in document && 'addEventListener' in window ) { 1310 body.addEventListener( 'mousedown', function() { 1311 body.classList.add( 'ast-mouse-clicked' ); 1312 } ); 1313 1314 body.addEventListener( 'keydown', function() { 1315 body.classList.remove( 'ast-mouse-clicked' ); 1316 } ); 1317 } 1318 } 1319 1320 /** 1321 * Scroll to specific hash link. 1322 * 1323 * @since x.x.x 1324 */ 1325 if ( astra.is_scroll_to_id ) { 1326 // Calculate the offset top of an element, accounting for nested elements. 1327 const getOffsetTop = (element) => { 1328 let offsetTop = 0; 1329 while (element) { 1330 offsetTop += element.offsetTop; 1331 element = element.offsetParent; 1332 } 1333 return offsetTop; 1334 } 1335 1336 const scrollToIDHandler = ( e, hash = null ) => { 1337 1338 let offset = 0; 1339 const siteHeader = document.querySelector('.site-header'); 1340 1341 if (siteHeader) { 1342 1343 // Check and add offset to scroll top if header is sticky. 1344 const stickyHeaders = siteHeader.querySelectorAll( 1345 'div[data-stick-support]' 1346 ); 1347 1348 if ( stickyHeaders.length > 0 ) { 1349 stickyHeaders.forEach( ( header ) => ( offset += header.clientHeight ) ); 1350 } else if ( typeof astraAddon !== 'undefined' && ! ( Number( astraAddon.sticky_hide_on_scroll ) && ! document?.querySelector( '.ast-header-sticked' ) ) ) { 1351 const fixedHeader = document.querySelector( '#ast-fixed-header' ); 1352 if ( fixedHeader ) { 1353 offset = fixedHeader?.clientHeight; 1354 if ( Number( astraAddon?.header_main_shrink ) ) { 1355 const headers = fixedHeader?.querySelectorAll( 1356 '.ast-above-header-wrap, .ast-below-header-wrap' 1357 ); 1358 headers?.forEach( () => ( offset -= 10 ) ); 1359 } 1360 } 1361 } 1362 1363 const href = hash ? hash : e.target?.closest( 'a' ).hash; 1364 if (href) { 1365 const scrollId = document.querySelector(href); 1366 if (scrollId) { 1367 const elementOffsetTop = getOffsetTop( scrollId ); 1368 if ( typeof astraAddon !== 'undefined' && Number( astraAddon.sticky_hide_on_scroll ) && window?.scrollY < elementOffsetTop ) { 1369 offset = 0; 1370 } 1371 1372 const scrollOffsetTop = elementOffsetTop - offset; 1373 if( scrollOffsetTop ) { 1374 astraSmoothScroll( e, scrollOffsetTop ); 1375 } 1376 } 1377 } 1378 } 1379 } 1380 1381 let hashLinks = []; 1382 const links = document.querySelectorAll( 1383 '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-"])' 1384 ); 1385 if (links) { 1386 for (const link of links) { 1387 if (link.href.split("#")[0] !== location.href.split("#")[0]) { 1388 // Store the hash 1389 hashLinks.push({ 1390 hash: link.hash, 1391 url: link.href.split("#")[0], 1392 }); 1393 } else if (link.hash !== "") { 1394 link.addEventListener("click", scrollToIDHandler); 1395 } 1396 } 1397 } 1398 1399 window.addEventListener('DOMContentLoaded', (event) => { 1400 for (let link of hashLinks) { 1401 if (window.location.href.split('#')[0] === link.url) { 1402 const siteHeader = document.querySelector('.site-header'); 1403 let offset = 0; 1404 1405 // Check and add offset to scroll top if header is sticky. 1406 const headerHeight = siteHeader.querySelectorAll('div[data-stick-support]'); 1407 if (headerHeight) { 1408 headerHeight.forEach(single => { 1409 offset += single.clientHeight; 1410 }); 1411 } 1412 1413 const scrollId = document.querySelector(link.hash); 1414 if (scrollId) { 1415 const scrollOffsetTop = getOffsetTop(scrollId) - offset; 1416 if (scrollOffsetTop) { 1417 astraSmoothScroll(event, scrollOffsetTop); 1418 } 1419 } 1420 } 1421 } 1422 1423 // If there is a hash in the URL when the page loads, scroll to that element after a short delay. 1424 if ( location.hash ) { 1425 setTimeout( () => scrollToIDHandler( new Event( 'click' ), location.hash ), 750 ); 1426 } 1427 }); 1428 } 1429 1430 /** 1431 * Scroll to top. 1432 * 1433 * @since x.x.x 1434 */ 1435 if ( astra.is_scroll_to_top ) { 1436 var masthead = document.querySelector( '#page header' ); 1437 var astScrollTop = document.getElementById( 'ast-scroll-top' ); 1438 1439 astScrollToTopHandler(masthead, astScrollTop); 1440 1441 window.addEventListener('scroll', function () { 1442 astScrollToTopHandler(masthead, astScrollTop); 1443 }); 1444 1445 astScrollTop.onclick = function(e){ 1446 astraSmoothScroll( e, 0 ); 1447 }; 1448 1449 astScrollTop.addEventListener( 'keydown' , function(e) { 1450 if ( e.key === 'Enter') { 1451 astraSmoothScroll( e, 0 ); 1452 } 1453 }); 1454 } 1455
1456 if ( astra?.is_dark_palette ) { 1457 document.documentElement.classList.add("astra-dark-mode-enable"); 1458 } else { 1459 document.documentElement.classList.remove("astra-dark-mode-enable"); 1460 } 1461 1462 /** 1463 * To remove the blank space when the store notice gets dismissed. 1464 * To adjust the height of the store notice when hanged over top. 1465 * 1466 * @since x.x.x 1467 */ 1468 window.addEventListener('DOMContentLoaded', (event) => { 1469 const isHangOverTopNotice = document.querySelector('.ast-woocommerce-store-notice-hanged'); 1470 const adjustBodyHeight = () => { 1471 const storeNotice = document.querySelector('.woocommerce-store-notice[data-position="hang-over-top"]'); 1472 document.body.style.paddingTop = `${storeNotice?.clientHeight || 0}px`; 1473 } 1474 1475 if (isHangOverTopNotice) { 1476 window.addEventListener('resize', adjustBodyHeight); 1477 setTimeout(() => adjustBodyHeight(), 0); 1478 } 1479 1480 document 1481 .querySelector('.woocommerce-store-notice__dismiss-link') 1482 ?.addEventListener('click', () => { 1483 if ( typeof wp === 'undefined' || ! wp?.customize ) { 1484 document.body.classList.remove('ast-woocommerce-store-notice-hanged'); 1485 window.removeEventListener('resize', adjustBodyHeight); 1486 document.body.style.paddingTop = 0; 1487 } 1488 }); 1489 }); 1490 1491})(); 1492 1493// Accessibility improvement for menu items. 1494document.addEventListener('DOMContentLoaded', function () { 1495 const submenuToggles = document.querySelectorAll('.menu-link .dropdown-menu-toggle'); 1496 1497 const menuItemsWithSubmenu = document.querySelectorAll('.menu-item-has-children > a'); 1498 1499 // Ensuring the submenu toggle action is handled with appropriate CSS, with cross browser compatibility for Enter key press. 1500 menuItemsWithSubmenu.forEach(item => { 1501 item.addEventListener('keydown', function(event) { 1502 if (event.key === 'Enter') { 1503 const submenu = item.nextElementSibling; 1504 if (submenu && submenu.classList.contains('sub-menu')) { 1505 submenu.classList.toggle('ast-visible'); 1506 const ariaExpanded = item.getAttribute('aria-expanded') === 'false' ? 'true' : 'false'; 1507 item.setAttribute('aria-expanded', ariaExpanded); 1508 } 1509 } 1510 }); 1511 }); 1512 1513 // Add event listeners for focus, blur, and keydown events. 1514 submenuToggles.forEach(toggle => { 1515 toggle.addEventListener('focus', () => updateAriaExpanded(toggle)); 1516 toggle.addEventListener('blur', () => updateAriaExpanded(toggle)); 1517 toggle.addEventListener('keydown', event => { 1518 if (event.key === 'Enter' || event.key === ' ') { 1519 event.preventDefault(); 1520 toggleAriaExpanded(toggle); 1521 } 1522 }); 1523 }); 1524 1525 // Add event listener for Escape key press to close all submenus. 1526 document.addEventListener('keydown', event => { 1527 if (event.key === 'Escape') { 1528 closeAllSubmenus(); 1529 } 1530 }); 1531 1532 /** 1533 * Updates the `aria-expanded` attribute based on submenu visibility. 1534 * @param {HTMLElement} toggle - The toggle element. 1535 */ 1536 function updateAriaExpanded(toggle) { 1537 const menuItemLink = toggle.closest('.menu-link'); 1538 const submenu = menuItemLink.nextElementSibling; 1539 const isSubmenuVisible = submenu.classList.contains('toggled-on'); 1540 menuItemLink.setAttribute('aria-expanded', isSubmenuVisible ? 'true' : 'false'); 1541 } 1542 1543 /** 1544 * Toggles the `aria-expanded` attribute for a given toggle element. 1545 * @param {HTMLElement} toggle - The toggle element. 1546 */ 1547 function toggleAriaExpanded(toggle) { 1548 const menuItemLink = toggle.closest('.menu-link'); 1549 const currentState = menuItemLink.getAttribute('aria-expanded'); 1550 menuItemLink.setAttribute('aria-expanded', currentState === 'true' ? 'false' : 'true'); 1551 } 1552 1553 /** 1554 * Closes all submenus by updating the `aria-expanded` attribute. 1555 */ 1556 function closeAllSubmenus() { 1557 submenuToggles.forEach(toggle => updateAriaExpanded(toggle)); 1558 } 1559 1560 // This event listener is triggered when the device orientation changes, and it dispatches a 'resize' event to ensure layout adjustments are made. 1561 window.addEventListener( 'orientationchange', () => { 1562 setTimeout( () => window.dispatchEvent( new Event( 'resize' ) ), 50 ); 1563 } ); 1564}); 1565 1566// Accessibility improvement for product card quick view and add to cart buttons. 1567document.addEventListener('DOMContentLoaded', () => { 1568 const thumbnailWraps = document.querySelectorAll('.astra-shop-thumbn
1568ail-wrap'); 1569 1570 thumbnailWraps.forEach(wrap => { 1571 const focusableElements = wrap.querySelectorAll('a, span'); 1572 1573 focusableElements.forEach(el => { 1574 el.addEventListener('focus', () => { 1575 wrap.querySelectorAll('.ast-on-card-button, .ast-quick-view-trigger').forEach(btn => { 1576 btn.style.opacity = '1'; 1577 btn.style.visibility = 'visible'; 1578 btn.style.borderStyle = 'none'; 1579 }); 1580 }); 1581 1582 el.addEventListener('blur', () => { 1583 // Added Check to check if child elements are still focused. 1584 const isAnyFocused = Array.from(focusableElements).some(child => child === document.activeElement); 1585 if (!isAnyFocused) { 1586 wrap.querySelectorAll('.ast-on-card-button, .ast-quick-view-trigger').forEach(btn => { 1587 btn.style.opacity = ''; 1588 btn.style.visibility = ''; 1589 }); 1590 } 1591 }); 1592 }); 1593 }); 1594});
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.