1window.addEventListener('load', function () { 2 console.log('Page fully loaded'); 3}); 4 5 6/* ============================================================ 7 * Big Top Leadership Biography Modals 8 * ============================================================ */ 9 10document.addEventListener('DOMContentLoaded', function () { 11 12 const cards = document.querySelectorAll('.bt-leadership-card'); 13 const modals = document.querySelectorAll('.bt-leadership-modal'); 14 15 if (!cards.length) { 16 return; 17 } 18 19 /* 20 * Divi containers can create their own stacking contexts. Moving the 21 * dialogs directly under <body> lets the backdrop cover the complete 22 * viewport, including the site header and WordPress admin bar. 23 */ 24 modals.forEach(function (modal) { 25 document.body.appendChild(modal); 26 }); 27 28 let activeModal = null; 29 let activeTrigger = null; 30 31 function getFocusableElements(modal) { 32 return Array.from( 33 modal.querySelectorAll( 34 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])' 35 ) 36 ).filter(function (element) { 37 return !element.hasAttribute('hidden'); 38 }); 39 } 40 41 function openModal(modal, trigger) { 42 43 if (!modal) { 44 return; 45 } 46 47 activeModal = modal; 48 activeTrigger = trigger; 49 50 modal.hidden = false; 51 trigger.setAttribute('aria-expanded', 'true'); 52 document.body.classList.add('bt-leadership-modal-open'); 53 54 const closeButton = modal.querySelector('.bt-leadership-modal__close'); 55 56 if (closeButton) { 57 closeButton.focus(); 58 } 59 } 60 61 function closeModal(modal) { 62 63 if (!modal) { 64 return; 65 } 66 67 modal.hidden = true; 68 document.body.classList.remove('bt-leadership-modal-open'); 69 70 if (activeTrigger) { 71 activeTrigger.setAttribute('aria-expanded', 'false'); 72 activeTrigger.focus(); 73 } 74 75 activeModal = null; 76 activeTrigger = null; 77 } 78 79 cards.forEach(function (card) { 80 card.addEventListener('click', function () { 81 const modalId = card.getAttribute('data-modal-target'); 82 openModal(document.getElementById(modalId), card); 83 }); 84 }); 85 86 modals.forEach(function (modal) { 87 const closeButton = modal.querySelector('.bt-leadership-modal__close'); 88 const backdrop = modal.querySelector('.bt-leadership-modal__backdrop'); 89 90 if (closeButton) { 91 closeButton.addEventListener('click', function () { 92 closeModal(modal); 93 }); 94 } 95 96 if (backdrop) { 97 backdrop.addEventListener('click', function () { 98 closeModal(modal); 99 }); 100 } 101 }); 102 103 document.addEventListener('keydown', function (event) { 104 105 if (!activeModal) { 106 return; 107 } 108 109 if (event.key === 'Escape') { 110 event.preventDefault(); 111 closeModal(activeModal); 112 return; 113 } 114 115 if (event.key !== 'Tab') { 116 return; 117 } 118 119 const focusable = getFocusableElements(activeModal); 120 121 if (!focusable.length) { 122 event.preventDefault(); 123 return; 124 } 125 126 const first = focusable[0]; 127 const last = focusable[focusable.length - 1]; 128 129 if (event.shiftKey && document.activeElement === first) { 130 event.preventDefault(); 131 last.focus(); 132 } else if (!event.shiftKey && document.activeElement === last) { 133 event.preventDefault(); 134 first.focus(); 135 } 136 }); 137 138}); 139 140document.addEventListener('DOMContentLoaded', function () { 141 document.querySelectorAll('.et_pb_post a.more-link').forEach(function (link) { 142 link.textContent = 'Read More'; 143 }); 144}); 145 146 147/* ============================================================ 148 * Big Top Custom Mega Menus 149 * Desktop connection 150 * Markets + Use Cases + Accessories + Services + Advantages + Company 151 * Sticky-header compatible 152 * ============================================================ */ 153 154document.addEventListener('DOMContentLoaded', function () { 155 156 const layer = document.getElementById('bt-mega-layer'); 157 158 if (!layer) { 159 return; 160 } 161 162 163 /* ------------------------------------------------------------ 164 * Configuration 165 * ------------------------------------------------------------ */ 166 167 const megaMenus = { 168 markets: { 169 triggerSelector: '.bt-mega-trigger--markets', 170 panelId: 'bt-mega-panel-markets' 171 }, 172 173 'use-cases': { 174 triggerSelector: '.bt-mega-trigger--use-cases', 175 panelId: 'bt-mega-panel-use-cases' 176 }, 177 178 accessories: { 179 triggerSelector: '.bt-mega-trigger--accessories', 180 panelId: 'bt-mega-panel-accessories' 181 }, 182 183 services: { 184 triggerSelector: '.bt-mega-trigger--services', 185 panelId: 'bt-mega-panel-services' 186 }, 187 188 advantages: { 189 triggerSelector: '.bt-mega-trigger--advantages', 190 panelId: 'bt-mega-panel-advantages' 191 }, 192 193 company: { 194 triggerSelector: '.bt-mega-trigger--company', 195 panelId: 'bt-mega-panel-company' 196 } 197 }; 198 199
200 let closeTimer = null; 201 let activeTrigger = null; 202 let activePanel = null; 203 204 205 /* ------------------------------------------------------------ 206 * Identify Mega Trigger 207 * ------------------------------------------------------------ */ 208 209 function getMegaItemFromElement(element) { 210 211 if (!element) { 212 return null; 213 } 214 215 const marketsTrigger = 216 element.closest('.bt-mega-trigger--markets'); 217 218 if (marketsTrigger) { 219 return { 220 trigger: marketsTrigger, 221 panel: document.getElementById( 222 megaMenus.markets.panelId 223 ) 224 }; 225 } 226 227 228 const useCasesTrigger = 229 element.closest('.bt-mega-trigger--use-cases'); 230 231 if (useCasesTrigger) { 232 return { 233 trigger: useCasesTrigger, 234 panel: document.getElementById( 235 megaMenus['use-cases'].panelId 236 ) 237 }; 238 } 239 240 const accessoriesTrigger = 241 element.closest('.bt-mega-trigger--accessories'); 242 243 if (accessoriesTrigger) { 244 return { 245 trigger: accessoriesTrigger, 246 panel: document.getElementById( 247 megaMenus.accessories.panelId 248 ) 249 }; 250 } 251 252 const servicesTrigger = 253 element.closest('.bt-mega-trigger--services'); 254 255 if (servicesTrigger) { 256 return { 257 trigger: servicesTrigger, 258 panel: document.getElementById( 259 megaMenus.services.panelId 260 ) 261 }; 262 } 263 264 const advantagesTrigger = 265 element.closest('.bt-mega-trigger--advantages'); 266 267 if (advantagesTrigger) { 268 return { 269 trigger: advantagesTrigger, 270 panel: document.getElementById( 271 megaMenus.advantages.panelId 272 ) 273 }; 274 } 275 276 const companyTrigger = 277 element.closest('.bt-mega-trigger--company'); 278 279 if (companyTrigger) { 280 return { 281 trigger: companyTrigger, 282 panel: document.getElementById( 283 megaMenus.company.panelId 284 ) 285 }; 286 } 287 288 return null; 289 } 290 291 292 /* ------------------------------------------------------------ 293 * Find the Active / Sticky Header Container 294 * ------------------------------------------------------------ */ 295 296 function getActiveHeaderContainer(trigger) { 297 298 let element = trigger; 299 300 while (element && element !== document.body) { 301 302 const styles = window.getComputedStyle(element); 303 304 if ( 305 styles.position === 'fixed' || 306 styles.position === 'sticky' 307 ) { 308 return element; 309 } 310 311 element = element.parentElement; 312 } 313 314 315 /* 316 * Fall back to the Divi Theme Builder header. 317 */ 318 return trigger.closest('.et-l--header'); 319 } 320 321 322 /* ------------------------------------------------------------ 323 * Position Mega Menu 324 * ------------------------------------------------------------ */ 325 326 function positionMegaMenu(trigger) { 327 328 const header = getActiveHeaderContainer(trigger); 329 330 if (!header) { 331 return; 332 } 333 334 const rect = header.getBoundingClientRect(); 335 336 337 /* 338 * The mega menu follows the viewport rather than the 339 * document. This keeps it attached to Divi's sticky header 340 * regardless of scroll position. 341 */ 342 layer.style.position = 'fixed'; 343 layer.style.top = rect.bottom + 'px'; 344 layer.style.left = '0'; 345 layer.style.width = '100%'; 346 } 347 348 349 /* ------------------------------------------------------------ 350 * Reset Trigger States 351 * ------------------------------------------------------------ */ 352 353 function resetTriggerStates() { 354 355 document.querySelectorAll( 356 '.bt-mega-trigger--markets > a, ' + 357 '.bt-mega-trigger--use-cases > a, ' + 358 '.bt-mega-trigger--accessories > a, ' + 359 '.bt-mega-trigger--services > a, ' + 360 '.bt-mega-trigger--advantages > a, ' + 361 '.bt-mega-trigger--company > a' 362 ).forEach(function (link) { 363 364 link.setAttribute('aria-haspopup', 'true'); 365 link.setAttribute('aria-expanded', 'false'); 366 367 }); 368 } 369 370 371 resetTriggerStates(); 372 373 374 /* ------------------------------------------------------------ 375 * Close Mega Menu 376 * ------------------------------------------------------------ */ 377 378 function closeMegaMenu() { 379 380 clearTimeout(closeTimer); 381 382 layer.classList.remove('is-open'); 383 layer.setAttribute('aria-hidden', 'true'); 384 385 386 document.querySelectorAll('.bt-mega-panel').forEach( 387 function (panel) { 388 panel.classList.remove('is-open'); 389 } 390 ); 391 392 393 document.querySelectorAll( 394 '.bt-mega-trigger--markets > a, ' + 395 '.bt-mega-trigger--use-cases > a, ' + 396 '.bt-mega-trigger--accessories > a, ' + 397 '.bt-mega-trigger--services > a, ' + 398 '.bt-mega-trigger--advantages > a, ' + 399 '.bt-mega-trigger--company > a' 400 ).forEach(function (link) { 401 402 link.setAttribute( 403 'aria-expanded', 404 'false' 405 ); 406 407 }); 408 409 410 activeTrigger = null; 411 activePanel = null; 412 } 413 414 415 /* ------------------------------------------------------------ 416 * Open Mega Menu 417 * ------------------------------------------------------------ */ 418 419 function openMegaMenu(item) { 420 421 if ( 422 window.innerWidth <= 980 || 423 !item || 424 !item.trigger || 425 !item.panel 426 ) { 427 return; 428 } 429 430 clearTimeout(closeTimer); 431 432 positionMegaMenu(item.trigger); 433 434 435 /* 436 * Hide whichever panel was previously open. 437 */ 438 document.querySelectorAll('.bt-mega-panel').forEach( 439 function (panel) { 440 441 if (panel !== item.panel) { 442 panel.classList.remove('is-open'); 443 } 444 445 } 446 ); 447 448 449 /* 450 * Reset all current trigger copies.
451 * This also handles Divi sticky-header duplicates. 452 */ 453 document.querySelectorAll( 454 '.bt-mega-trigger--markets > a, ' + 455 '.bt-mega-trigger--use-cases > a, ' + 456 '.bt-mega-trigger--accessories > a, ' + 457 '.bt-mega-trigger--services > a, ' + 458 '.bt-mega-trigger--advantages > a, ' + 459 '.bt-mega-trigger--company > a' 460 ).forEach(function (link) { 461 462 link.setAttribute( 463 'aria-expanded', 464 'false' 465 ); 466 467 }); 468 469 470 item.panel.classList.add('is-open'); 471 layer.classList.add('is-open'); 472 473 layer.setAttribute( 474 'aria-hidden', 475 'false' 476 ); 477 478 479 const triggerLink = 480 item.trigger.querySelector('a'); 481 482 if (triggerLink) { 483 484 triggerLink.setAttribute( 485 'aria-expanded', 486 'true' 487 ); 488 } 489 490 491 activeTrigger = item.trigger; 492 activePanel = item.panel; 493 } 494 495 496 /* ------------------------------------------------------------ 497 * Delayed Close 498 * ------------------------------------------------------------ */ 499 500 function scheduleClose() { 501 502 clearTimeout(closeTimer); 503 504 closeTimer = setTimeout(function () { 505 closeMegaMenu(); 506 }, 350); 507 } 508 509 510 /* ------------------------------------------------------------ 511 * Delegated Hover 512 * 513 * Important: 514 * We do NOT bind only to the original header. 515 * This allows Divi's sticky header / duplicated nav to work too. 516 * ------------------------------------------------------------ */ 517 518 document.addEventListener('mouseover', function (event) { 519 520 const item = 521 getMegaItemFromElement(event.target); 522 523 if (!item) { 524 return; 525 } 526 527 528 /* 529 * Ignore mouse movement between children inside 530 * the same trigger. 531 */ 532 if ( 533 event.relatedTarget && 534 item.trigger.contains( 535 event.relatedTarget 536 ) 537 ) { 538 return; 539 } 540 541 openMegaMenu(item); 542 }); 543 544 545 document.addEventListener('mouseout', function (event) { 546 547 const item = 548 getMegaItemFromElement(event.target); 549 550 if (!item) { 551 return; 552 } 553 554 555 /* 556 * Don't close when simply moving between elements 557 * within the same nav item. 558 */ 559 if ( 560 event.relatedTarget && 561 item.trigger.contains( 562 event.relatedTarget 563 ) 564 ) { 565 return; 566 } 567 568 scheduleClose(); 569 }); 570 571 572 /* ------------------------------------------------------------ 573 * Keep Open While Cursor Is Over Mega Panel / Hover Bridge 574 * ------------------------------------------------------------ */ 575 576 layer.addEventListener('mouseenter', function () { 577 clearTimeout(closeTimer); 578 }); 579 580 layer.addEventListener('mouseleave', scheduleClose); 581 582 583 /* ------------------------------------------------------------ 584 * Delegated Click Support 585 * ------------------------------------------------------------ */ 586 587 document.addEventListener('click', function (event) { 588 589 const item = 590 getMegaItemFromElement(event.target); 591 592 593 /* 594 * Top-level mega trigger clicked. 595 */ 596 if (item) { 597 598 if (window.innerWidth <= 980) { 599 return; 600 } 601 602 const link = 603 event.target.closest('a'); 604 605 606 if ( 607 link && 608 ( 609 activePanel !== item.panel || 610 !layer.classList.contains('is-open') 611 ) 612 ) { 613 614 event.preventDefault(); 615 openMegaMenu(item); 616 } 617 618 return; 619 } 620 621 622 /* 623 * Click outside closes. 624 */ 625 if (!layer.contains(event.target)) { 626 closeMegaMenu(); 627 } 628 629 }); 630 631 632 /* ------------------------------------------------------------ 633 * Escape Closes 634 * ------------------------------------------------------------ */ 635 636 document.addEventListener('keydown', function (event) { 637 638 if (event.key !== 'Escape') { 639 return; 640 } 641 642 643 const triggerLink = 644 activeTrigger 645 ? activeTrigger.querySelector('a') 646 : null; 647 648 649 closeMegaMenu(); 650 651 652 if (triggerLink) { 653 triggerLink.focus(); 654 } 655 656 }); 657 658 659 /* ------------------------------------------------------------ 660 * Scroll 661 * 662 * Recalculate the position while the sticky header changes 663 * position or dimensions. 664 * ------------------------------------------------------------ */ 665 666 window.addEventListener( 667 'scroll', 668 function () { 669 670 if ( 671 layer.classList.contains('is-open') && 672 activeTrigger 673 ) { 674 positionMegaMenu(activeTrigger); 675 } 676 677 }, 678 { passive: true } 679 ); 680 681 682 /* ------------------------------------------------------------ 683 * Resize 684 * ------------------------------------------------------------ */ 685 686 window.addEventListener('resize', function () { 687 688 if (window.innerWidth <= 980) { 689 690 closeMegaMenu(); 691 return; 692 } 693 694 695 if ( 696 layer.classList.contains('is-open') && 697 activeTrigger 698 ) { 699 positionMegaMenu(activeTrigger); 700 } 701 702 }); 703 704});
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.