1/* Toggles active classes based on scroll position for side-nav */ 2 3const links = document.querySelectorAll(".bhc-solutions__navCategory"); 4const sections = document.querySelectorAll(".bhc-solution"); 5 6function initMap() { 7 var input = document.getElementById("addressInput"); 8 var autocomplete = new google.maps.places.Autocomplete(input); 9 var selectedAddress = ""; 10 11 // listen for user interaction with the page 12 autocomplete.addListener("place_changed", 13 async () => { 14 var place = autocomplete.getPlace(); 15 if (!place.geometry) { 16 console.log('Location from Autocomplete Bar by Enter Key'); 17 selectedAddress = $(".pac-container .pac-item:first").text(); 18 } else { 19 console.log('Location from Autocomplete Bar Selection'); 20 selectedAddress = place.formatted_address; 21 } 22 //console.log('Selected Address ' + selectedAddress) 23 location.href = "/find-a-center?address=" + encodeURIComponent(selectedAddress); 24 }); 25 if (input !== null && input !== undefined) { 26 input.addEventListener('keydown', function (event) { 27 if ((event.key === 'Enter' || event.keycode === 13) && !autocomplete.getPlace()) { 28 const inputText = input.value; 29 const autocompleteService = new google.maps.places.AutocompleteService(); 30 autocompleteService.getPlacePredictions({ input: inputText }, function (predictions, status) { 31 if (status === google.maps.places.PlacesServiceStatus.OK && predictions && predictions.length > 0) { 32 const firstPrediction = predictions[0].description; 33 location.href = "/find-a-center?address=" + encodeURIComponent(firstPrediction); 34 } 35 }); 36 } 37 }); 38 } 39} 40 41function changeNavState() { 42 let index = sections.length; 43 if (index > 0) { 44 console.log('sections length:' + sections.length); 45 while (--index && window.scrollY + 350 < sections[index].offsetTop) { } 46 47 links.forEach((link) => link.classList.remove("active")); 48 links[index].classList.add("active"); 49 } 50} 51 52changeNavState(); 53window.addEventListener("scroll", changeNavState); 54 55/* Toggles animation class when cicrcle chart enters viewport */ 56 57(function () { 58 var elements; 59 var windowHeight; 60 61 function init() { 62 elements = document.querySelectorAll(".bhc-circle"); 63 windowHeight = window.innerHeight; 64 } 65 66 function checkPosition() { 67 for (var i = 0; i < elements.length; i++) { 68 var element = elements[i]; 69 var positionFromTop = elements[i].getBoundingClientRect().top; 70 71 if (positionFromTop - windowHeight <= 0) { 72 element.classList.add("bhc-drawCircle"); 73 } 74 } 75 } 76 window.addEventListener("scroll", checkPosition); 77 window.addEventListener("resize", init); 78 79 init(); 80 checkPosition(); 81})(); 82 83// Corporate Home Solutions Container JS 84$(".toggle.-onHeading").click(function () { 85 $(".bhc-solution").addClass("-showNav"); 86 $(".bhc-solutions__nav").addClass("-showNav"); 87 $(".-onHeading").addClass("hide"); 88 $(".homeModal").addClass("-showBackground"); 89 $("#closeNav").addClass("show"); 90}); 91$("#closeNav").click(function () { 92 $(".bhc-solution").removeClass("-showNav"); 93 $(".bhc-solutions__nav").removeClass("-showNav"); 94 $(".-onHeading").removeClass("hide"); 95 $(".homeModal").removeClass("-showBackground"); 96 $("#closeNav").removeClass("show"); 97}); 98$('.bhc-icon-modal-close-x').click(function () { 99 $("#subnav-search-desktop-top").addClass("hide"); 100}); 101$('.nav-link-search').click(function () { 102 $("#subnav-search-desktop-top").removeClass("hide"); 103}); 104 105/* JS for Show and Hide Feature */ 106const buttons = document.querySelectorAll(".js-btn-see-more"); 107buttons.forEach(button => { 108 button.addEventListener("click", function () { 109 document.querySelectorAll(".hidden-see-more").forEach(el => { 110 el.classList.remove("hidden-see-more"); 111 }); 112 button.style.display = "none"; 113 });
114}); 115 116$("#meet-our-staff .js-btn-see-less").on("click", function () { 117 scrollToElement($("#meet-our-staff")); 118}) 119function scrollToElement($element) { 120 $('html, body').animate({ 121 scrollTop: $element.offset().top 122 }, 0); 123 return false; 124} 125 126const showMoreBtnDesktop = document.querySelector(".js-btn-see-more-desktop"); 127const showLessBtnDesktop = document.querySelector(".js-btn-see-less-desktop"); 128const showMoreBtnMobile = document.querySelector(".js-btn-see-more-mobile"); 129const showLessBtnMobile = document.querySelector(".js-btn-see-less-mobile"); 130const desktopTiles = document.querySelectorAll(".hidden-xs-corp .js-tile-see-more.tile-see-more"); 131const mobileTiles = document.querySelectorAll(".visible-xs-block-corp .panel-teacher-wrap.tile-see-more"); 132 133document.addEventListener("DOMContentLoaded", function () { 134 const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 135 const isBrowserStack = navigator.userAgent.includes('BrowserStack'); 136 const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); 137 const isIOSBrowser = isIOS || (isBrowserStack && isSafari); 138 139 console.log("Device detection:", { 140 userAgent: navigator.userAgent, 141 isIOS: isIOS, 142 isBrowserStack: isBrowserStack, 143 isSafari: isSafari, 144 isIOSBrowser: isIOSBrowser 145 }); 146 147 148 // Function to hide desktop tiles beyond the first 3 149 function hideExtraDesktopTiles() { 150 for (let i = 0; i < desktopTiles.length; i++) { 151 if (i >= 3) { 152 desktopTiles[i].classList.add("hidden-see-more"); 153 if (isIOSBrowser) { 154 desktopTiles[i].style.display = "none !important"; 155 } 156 } else { 157 desktopTiles[i].classList.remove("hidden-see-more"); 158 if (isIOSBrowser) { 159 desktopTiles[i].style.display = "block !important"; 160 } 161 } 162 } 163 } 164 165 // Function to show all desktop tiles 166 function showAllDesktopTiles() { 167 for (let i = 0; i < desktopTiles.length; i++) { 168 desktopTiles[i].classList.remove("hidden-see-more"); 169 170 //desktopTiles[i].setAttribute('tabindex', '0'); // Ensure it's focusable 171 //desktopTiles[i].focus(); 172 173 if (isIOSBrowser) { 174 desktopTiles[i].style.display = "block !important"; 175 } 176 // Focus on the heading within the 4th card for better accessibility 177 const headingElement = desktopTiles[3].querySelector("h3.txt-curriculum-wheel-title"); 178 if (headingElement) { 179 headingElement.setAttribute('tabindex', '0'); 180 headingElement.focus(); 181 } else { 182 // Fallback to focusing on the card itself 183 desktopTiles[3].setAttribute('tabindex', '0'); 184 desktopTiles[3].focus(); 185 } 186 187 } 188 } 189 function hideExtraMobileTiles() { 190 for (let i = 0; i < mobileTiles.length; i++) { 191 if (i >= 3) { 192 mobileTiles[i].classList.add("hidden-see-more"); 193 if (isIOSBrowser) { 194 mobileTiles[i].style.display = "none !important"; 195 } 196 } else { 197 mobileTiles[i].classList.remove("hidden-see-more"); 198 if (isIOSBrowser) { 199 mobileTiles[i].style.display = "block !important"; 200 } 201 } 202 203 } 204 } 205 206 // Function to show all mobile tiles 207 function showAllMobileTiles() { 208 for (let i = 0; i < mobileTiles.length; i++) { 209 mobileTiles[i].classList.remove("hidden-see-more"); 210 if (isIOSBrowser) { 211 mobileTiles[i].style.display = "block !important"; 212 } 213 if (mobileTiles.length >= 4) { 214 // Try to focus on the heading within the 4th mobile card 215 const headingElement = mobileTiles[3].querySelector("h3.txt-curriculum-wheel-title"); 216 if (headingElement) { 217 headingElement.setAttribute('tabindex', '0'); 218 headingElement.focus(); 219 } else { 220 // Fallback to focusing on the card itself 221 mobileTiles[3].setAttribute('tabindex', '0'); 222 mobileTiles[3].focus(); 223 } 224 } 225 226 } 227 } 228 229 // Apply iOS-specific CSS fixes 230 function applyIOSFixes() { 231 // Add iOS-specific style overrides 232 const styleEl = document.createElement('style'); 233 styleEl.innerHTML = ` 234 /* @media (max-width: 480px) {*/ 235 @media (max-width: 745px) { 236 .visible-xs-block-corp { 237 display: block !important; 238 } 239 .hidden-xs-corp { 240 display: none !important; 241 } 242 .visible-xs-block-corp .panel-teacher-wrap.tile-see-more.hidden-see-more { 243 display: none !important; 244 } 245 .panel-teacher-wrap { 246 background-color: white; 247 margin-bottom: 10px; 248 border-radius: 8px; 249 width: 100%; 250 } 251 .panel-teacher-link { 252 display: block; 253 padding: 15px; 254 position: relative; 255 } 256 .panel-teacher-link .arrow-rotating { 257 transform: rotate(0deg) !important; 258 transition: transform 0.3s; 259 } 260 .panel-teacher-link:not(.collapsed) .arrow-rotating { 261 transform: rotate(90deg) !important; 262 } 263 .panel-teacher-content-expandable { 264 transition: height 0.35s ease; 265 } 266 .panel-teacher-link.collapsed + .panel-teacher-content-expandable { 267 height: 0 !important; 268 display: none !important; 269 overflow: hidden; 270 } 271 .teacher-accordion-group .tile-teacher-img-wrap 272 Specificity: (0,3,0) 273 { 274 margin: 0; 275 padding: 0; 276 } 277 .teacher-accordion-group .tile-teacher-img-wrap { 278 display: inline-block; 279 vertical-align: top; 280 background-size: cover; 281 background-position: 50%; 282 background-repeat: no-repeat; 283 width: 65px; 284 height: 57px; 285 overflow: hidden; 286 } 287 .tile-teacher-img-wrap { 288 width: 67px; 289 border-radius: 8px; 290 } 291 292 .teacher-accordion-group .txt-tile-description { 293 color: #4a4a4a; 294 line-height: 1.285; 295 padding-top: 14px; 296 padding-bottom: 10px; 297 } 298 .txt-rating-notes-sm { 299 font-size: 1.4rem; 300 line-height: 1.375; 301 letter-spacing: normal; 302 } 303 .btn.btn-large { 304 padding: 10px 30px; 305 border-radius: 5px; 306 } 307 .btn-hollow { 308 border: 2px solid #f2a900; 309 background-color: transparent; 310 color: #233956; 311 } 312 .btn-large { 313 font-size: 1.6rem; 314 line-height: 1.25; 315 letter-spacing: 0; 316 } 317 318 .teacher-accordion-group .profile-text-wrap { 319 display: inline-block; 320 color: #fff; 321 padding-left: 15px; 322 } 323 .teacher-accordion-group .txt-curriculum-wheel-title { 324 color: #231f20; 325 padding-bottom: 2px; 326 } 327 .teacher-accordion-group .txt-tile-subhead { 328 color: #5d5e60; 329 } 330 .learn-more-wrap { 331 margin-top: 32px; 332 } 333 .collapse.in { 334 display: block; 335 height:auto!important; 336 } 337 .btn.btn-large { 338 display: flex; 339 width: 343px; 340 justify-content: space-between; 341 height: 60p!importantx; 342 padding: 16px 28px!important; 343 justify-content: center!important; 344 align-items: center!important; 345 gap: 12px!important; 346 border-radius: 8px!important; 347border: 2px solid var(--yellow-500, #F0BD1B)!important; 348 } 349 .module-padding { 350 padding-bottom: 56px; 351 padding-top: 56px; 352 } 353 354 .teacher-accordion-group .arrow-rotating { 355 color: #5d5e60; 356 position: absolute; 357 right: 20px; 358 top: 35px; 359 } 360 .arrow-rotating { 361 font-size: 24px; 362 } 363 .btn-back-arrow:before, .faq-module .faq-nav-question-list li a:after, .footer-module .footer-breadcrumb-link+.footer-breadcrumb-link:before, .root-page-module .panel-center-link:after, .tag-enrolling:before, .tile-events .txt-tile-subhead:after, .tiles-module-slider-wrap .slick-arrow:before, [class*=" bh-icon-"], [class^=bh-icon-] { 364 speak: none; 365 font-style: normal; 366 font-weight: 400; 367 font-variant: normal; 368 text-transform: none; 369 line-height: 1; 370 -webkit-font-smoothing: antialiased; 371 -moz-osx-font-smoothing: grayscale; 372} } 373 `; 374 document.head.appendChild(styleEl); 375 376 // Fix mobile visibility classes 377 if (window.innerWidth < 768) { 378 document.querySelectorAll('.visible-xs-block-corp').forEach(el => { 379 el.style.display = 'block !important'; 380 }); 381 document.querySelectorAll('.hidden-xs-corp').forEach(el => { 382 el.style.display = 'none !important'; 383 }); 384 385 } 386
387 // Fix collapsed state and click behavior for accordion items 388 fixAccordions(); 389 } 390 391 function fixAccordions() { 392 const accordionLinks = document.querySelectorAll('.panel-teacher-link'); 393 accordionLinks.forEach(link => { 394 // Ensure initial state 395 if (!link.classList.contains('collapsed')) { 396 link.classList.add('collapsed'); 397 } 398 399 // Get associated content panel 400 const targetId = link.getAttribute('href') || link.getAttribute('data-target'); 401 if (targetId) { 402 const contentPanel = document.querySelector(targetId); 403 if (contentPanel) { 404 contentPanel.classList.remove('in'); 405 contentPanel.style.height = '0px'; 406 contentPanel.style.display = 'none'; 407 } 408 } 409 410 // Replace existing click handlers 411 link.removeEventListener('click', accordionClickHandler); 412 link.addEventListener('click', accordionClickHandler); 413 }); 414 } 415 416 function accordionClickHandler(e) { 417 e.preventDefault(); 418 e.stopPropagation(); 419 420 const link = this; 421 const wasCollapsed = link.classList.contains('collapsed'); 422 const targetId = link.getAttribute('href') || link.getAttribute('data-target'); 423 424 if (targetId) { 425 const contentPanel = document.querySelector(targetId); 426 427 if (wasCollapsed) { 428 // Expanding 429 link.classList.remove('collapsed'); 430 if (contentPanel) { 431 contentPanel.classList.add('in'); 432 contentPanel.style.height = contentPanel.scrollHeight + 'px'; 433 contentPanel.style.display = 'block'; 434 } 435 } else { 436 // Collapsing 437 link.classList.add('collapsed'); 438 if (contentPanel) { 439 contentPanel.classList.remove('in'); 440 contentPanel.style.height = '0px'; 441 setTimeout(function () { 442 contentPanel.style.display = 'none'; 443 }, 350); 444 } 445 } 446 } 447 return false; 448 } 449 450 // Initial setup function 451 function initialSetup() { 452 453 // Apply iOS-specific fixes if needed 454 if (isIOSBrowser) { 455 applyIOSFixes(); 456 } 457 458 // Set up desktop view 459 hideExtraDesktopTiles(); 460 if (showMoreBtnDesktop && showLessBtnDesktop) { 461 showLessBtnDesktop.style.display = "none"; 462 showMoreBtnDesktop.style.display = "inline-block"; 463 } 464 465 // Set up mobile view 466 hideExtraMobileTiles(); 467 if (showMoreBtnMobile && showLessBtnMobile) { 468 showLessBtnMobile.style.display = "none"; 469 showMoreBtnMobile.style.display = "inline-block"; 470 } 471 } 472 473 // Run initial setup 474 initialSetup(); 475 476 // Configure desktop button click handlers 477 if (showMoreBtnDesktop && showLessBtnDesktop) { 478 showMoreBtnDesktop.addEventListener("click", function () { 479 showAllDesktopTiles(); 480 showMoreBtnDesktop.style.display = "none"; 481 showLessBtnDesktop.style.display = "inline-block"; 482 }); 483 484 showLessBtnDesktop.addEventListener("click", function () { 485 hideExtraDesktopTiles(); 486 showLessBtnDesktop.style.display = "none"; 487 showMoreBtnDesktop.style.display = "inline-block"; 488 }); 489 } 490 491 // Configure mobile button click handlers 492 if (showMoreBtnMobile && showLessBtnMobile) { 493 showMoreBtnMobile.addEventListener("click", function () { 494 showAllMobileTiles(); 495 showMoreBtnMobile.style.display = "none"; 496 showLessBtnMobile.style.display = "inline-block"; 497 }); 498 499 showLessBtnMobile.addEventListener("click", function () { 500 hideExtraMobileTiles(); 501 showLessBtnMobile.style.display = "none"; 502 showMoreBtnMobile.style.display = "inline-block"; 503 }); 504 } 505 506 // Fallback for mobile buttons 507 const fallbackMoreBtn = document.querySelector(".visible-xs-block-corp .js-btn-see-more"); 508 const fallbackLessBtn = document.querySelector(".visible-xs-block-corp .js-btn-see-less"); 509 510 if ((!showMoreBtnMobile || !showLessBtnMobile) && fallbackMoreBtn && fallbackLessBtn) { 511 512 fallbackLessBtn.style.display = "none"; 513 514 fallbackMoreBtn.addEventListener("click", function () { 515 showAllMobileTiles(); 516 fallbackMoreBtn.style.display = "none"; 517 fallbackLessBtn.style.display = "inline-block"; 518 }); 519 520 fallbackLessBtn.addEventListener("click", function () { 521 hideExtraMobileTiles(); 522 fallbackLessBtn.style.display = "none"; 523 fallbackMoreBtn.style.display = "inline-block"; 524 }); 525 } 526 527 // Handle window resize events with improved iOS support 528 window.addEventListener("resize", function () { 529 const isMobileView = window.innerWidth < 768; 530 531 // Re-apply iOS fixes on resize 532 if (isIOSBrowser) { 533 // Ensure correct display based on viewport 534 if (isMobileView) { 535 document.querySelectorAll('.visible-xs-block-corp').forEach(el => { 536 el.style.display = 'block !important'; 537 }); 538 document.querySelectorAll('.hidden-xs-corp').forEach(el => { 539 el.style.display = 'none !important'; 540 }); 541 542 // Re-check mobile tiles 543 const allMobileVisible = Array.from(mobileTiles).every(tile => 544 !tile.classList.contains('hidden-see-more')); 545 546 if (showMoreBtnMobile && showLessBtnMobile) { 547 showMoreBtnMobile.style.display = allMobileVisible ? "none" : "inline-block"; 548 showLessBtnMobile.style.display = allMobileVisible ? "inline-block" : "none"; 549 } 550 } else { 551 // Desktop view 552 document.querySelectorAll('.visible-xs-block-corp').forEach(el => { 553 el.style.display = 'none !important'; 554 }); 555 document.querySelectorAll('.hidden-xs-corp').forEach(el => { 556 el.style.display = 'block !important'; 557 }); 558 559 // Re-check desktop tiles 560 const allDesktopVisible = Array.from(desktopTiles).every(tile => 561 !tile.classList.contains('hidden-see-more')); 562 563 if (showMoreBtnDesktop && showLessBtnDesktop) { 564 showMoreBtnDesktop.style.display = allDesktopVisible ? "none" : "inline-block"; 565 showLessBtnDesktop.style.display = allDesktopVisible ? "inline-block" : "none"; 566 } 567 } 568 } 569 });
570 571 // For iOS Safari, add a slight delay to make sure everything is properly rendered 572 if (isIOSBrowser) { 573 setTimeout(function () { 574 initialSetup(); 575 if (window.innerWidth < 768) { 576 document.querySelectorAll('.visible-xs-block-corp').forEach(el => { 577 el.style.display = 'block !important'; 578 }); 579 document.querySelectorAll('.hidden-xs-corp').forEach(el => { 580 el.style.display = 'none !important'; 581 }); 582 } 583 }, 300); 584 } 585}); 586 587 588// Configure desktop button click handlers 589if (showMoreBtnDesktop && showLessBtnDesktop) { 590 showMoreBtnDesktop.addEventListener("click", function () { 591 showAllDesktopTiles(); 592 showMoreBtnDesktop.style.display = "none"; 593 showLessBtnDesktop.style.display = "inline-block"; 594 }); 595 596 showLessBtnDesktop.addEventListener("click", function () { 597 hideExtraDesktopTiles(); // This function should keep first 3 visible 598 showLessBtnDesktop.style.display = "none"; 599 showMoreBtnDesktop.style.display = "inline-block"; 600 }); 601} 602 603// Configure mobile button click handlers 604if (showMoreBtnMobile && showLessBtnMobile) { 605 showMoreBtnMobile.addEventListener("click", function () { 606 showAllMobileTiles(); 607 showMoreBtnMobile.style.display = "none"; 608 showLessBtnMobile.style.display = "inline-block"; 609 }); 610 611 showLessBtnMobile.addEventListener("click", function () { 612 hideExtraMobileTiles(); // This function should keep first 3 visible 613 showLessBtnMobile.style.display = "none"; 614 showMoreBtnMobile.style.display = "inline-block"; 615 }); 616} 617 618/* ======================================================================== 619 * Bootstrap: transition.js v3.3.5 620 * https://getbootstrap.com/javascript/#transitions 621 * ======================================================================== 622 * Copyright 2011-2015 Twitter, Inc. 623 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 624 * ======================================================================== */ 625 626 627+ 628 629 function ($) { 630 'use strict'; 631 632 // CSS TRANSITION SUPPORT (Shoutout: https://www.modernizr.com/) 633 // ============================================================ 634 635 function transitionEnd() { 636 var el = document.createElement('bootstrap') 637 638 var transEndEventNames = { 639 WebkitTransition: 'webkitTransitionEnd', 640 MozTransition: 'transitionend', 641 OTransition: 'oTransitionEnd otransitionend', 642 transition: 'transitionend' 643 } 644 645 for (var name in transEndEventNames) { 646 if (el.style[name] !== undefined) { 647 return { end: transEndEventNames[name] } 648 } 649 } 650 651 return false // explicit for ie8 ( ._.) 652 } 653 654 // http://blog.alexmaccaw.com/css-transitions 655 $.fn.emulateTransitionEnd = function (duration) { 656 var called = false 657 var $el = this 658 $(this).one('bsTransitionEnd', function () { called = true }) 659 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 660 setTimeout(callback, duration) 661 return this 662 } 663 664 $(function () { 665 $.support.transition = transitionEnd() 666 667 if (!$.support.transition) return 668 669 $.event.special.bsTransitionEnd = { 670 bindType: $.support.transition.end, 671 delegateType: $.support.transition.end, 672 handle: function (e) { 673 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 674 } 675 } 676 }) 677 }(jQuery); 678 679// Disables Spacebar scrolling for Solutions nav jumpLinks, 680 681$('.bhc-solutions__jumpLink').on('keydown', function (e) { 682 return !(e.keyCode == 32); 683}); 684 685$(document).ready(function () { 686 // Global state for video tracking across all videos 687 var videoTrackingState = {}; 688 var currentActiveVideo = null; 689 690 // Create the missing trackVideoEvent function 691 function trackVideoEvent(provider, videoUrl, linkText) { 692 // Initialize dataLayer if it doesn't exist 693 window.dataLayer = window.dataLayer || []; 694 695 // Push video_start event to dataLayer 696 window.dataLayer.push({ 697 event: 'video_start', 698 video_provider: provider, 699 video_url: videoUrl, 700 link_text: linkText || '' 701 }); 702 } 703 704 // Make trackVideoEvent globally available 705 window.trackVideoEvent = trackVideoEvent; 706 707 // Initialize tracking for all videos on the page 708 function initializeAllVideoTracking() { 709 // Clear existing state 710 videoTrackingState = {}; 711 712 // Find all video containers - improved selector 713 var $videoContainers = $(".videoContent__iframe, .embed-responsive, .video-container, [class*='video']").filter(function() { 714 return $(this).find('iframe').length > 0 || $(this).is('iframe'); 715 }); 716 717 $videoContainers.each(function(index) { 718 var $videoContainer = $(this); 719 var $iframe = $videoContainer.find('iframe').first(); 720 721 // If this element is an iframe itself, use it 722 if ($videoContainer.is('iframe')) { 723 $iframe = $videoContainer; 724 $videoContainer = $videoContainer.parent(); 725 } 726 727 if ($iframe.length === 0) { 728 return; 729 } 730 731 var trackingVal = $videoContainer.data("tracking-cta"); 732 var trackingArr = trackingVal ? trackingVal.split(",") : null; 733 var linkText = trackingArr && trackingArr[0] ? trackingArr[0] : "Video"; 734 var linkSection = trackingArr && trackingArr[2] ? trackingArr[2] : "body"; 735 var videourl = $iframe.attr("src"); 736 var provider = "unknown"; 737 738 if (videourl) { 739 try { 740 var urlObj = new URL(videourl); 741 provider = urlObj.hostname.replace('www.', ''); 742 } catch(e) { 743 provider = 'unknown'; 744 } 745 } 746 747 // Get unique identifier for this video container 748 var videoId = $videoContainer.attr('id') || 749 $videoContainer.closest('[id]').attr('id') || 750 'video-' + index + '-' + Math.random().toString(36).substr(2, 5); 751 752 // Store tracking data for this video 753 videoTrackingState[videoId] = { 754 element: $videoContainer, 755 iframe: $iframe, 756 trackingVal: trackingVal, 757 trackingArr: trackingArr,
758 linkText: linkText, 759 linkSection: linkSection, 760 videourl: videourl, 761 provider: provider, 762 overIframe: false, 763 isFirstClick: true 764 }; 765 }); 766 } 767 768 // Get the currently active video (visible/active one) 769 function getCurrentActiveVideo() { 770 // Check for video containers that are active/visible 771 var $activeContainer = $('.videoContainer .container.-active, .videoContainer .container[aria-hidden="false"]').first(); 772 if ($activeContainer.length > 0) { 773 var activeId = $activeContainer.attr('id'); 774 return videoTrackingState[activeId] || null; 775 } 776 777 // Fallback to first video if no active one found 778 var firstVideoId = Object.keys(videoTrackingState)[0]; 779 return firstVideoId ? videoTrackingState[firstVideoId] : null; 780 } 781 782 // Setup pointer tracking for all video iframes 783 function setupPointerTracking() { 784 Object.keys(videoTrackingState).forEach(function(videoId) { 785 var videoState = videoTrackingState[videoId]; 786 787 // Remove any existing handlers 788 videoState.element.off('mouseover.videotrack mouseout.videotrack click.videotrack'); 789 videoState.iframe.off('mouseover.videotrack mouseout.videotrack'); 790 791 // Add hover tracking to container 792 videoState.element.on("mouseover.videotrack", function () { 793 // Reset all other video states 794 Object.keys(videoTrackingState).forEach(function(id) { 795 videoTrackingState[id].overIframe = false; 796 }); 797 798 // Set current video as active 799 videoState.overIframe = true; 800 currentActiveVideo = videoState; 801 }).on("mouseout.videotrack", function () { 802 videoState.overIframe = false; 803 if (currentActiveVideo === videoState) { 804 currentActiveVideo = null; 805 } 806 }); 807 808 // Add direct click tracking as fallback 809 videoState.element.on("click.videotrack", function(e) { 810 // Check if click is on or near iframe 811 var $target = $(e.target); 812 if ($target.is('iframe') || $target.closest('.embed-responsive').length > 0 || 813 $target.closest('.videoContent__iframe').length > 0) { 814 815 // Fire video_start event immediately 816 trackVideoEvent(videoState.provider, videoState.videourl, videoState.linkText); 817 818 // Mark as not first click for blur tracking 819 videoState.isFirstClick = false; 820 } 821 }); 822 823 // Also add hover tracking to iframe itself 824 videoState.iframe.on("mouseover.videotrack", function () { 825 videoState.overIframe = true; 826 currentActiveVideo = videoState; 827 }); 828 }); 829 } 830 831 // Detect click via window blur while cursor is over any iframe 832 $(window).off('blur.videotrack').on("blur.videotrack", function () { 833 // Check if we have an active video under cursor 834 var activeVideo = currentActiveVideo || getCurrentActiveVideo(); 835 836 if (!activeVideo || !activeVideo.overIframe) { 837 return; 838 } 839 840 // Fire video_start event 841 trackVideoEvent(activeVideo.provider, activeVideo.videourl, activeVideo.linkText); 842 843 // Mark as not first click 844 if (activeVideo.isFirstClick) { 845 activeVideo.isFirstClick = false; 846 } 847 }); 848 849 // Reinitialize when videos change (for carousel functionality) 850 function reinitializeVideoTracking() { 851 initializeAllVideoTracking(); 852 setupPointerTracking(); 853 } 854 855 // Watch for DOM changes to handle dynamically loaded videos 856 var observer = new MutationObserver(function(mutations) { 857 var shouldReinit = false; 858 mutations.forEach(function(mutation) { 859 if (mutation.type === 'attributes' || mutation.type === 'childList') { 860 // Check if video containers were added/modified 861 if ($(mutation.target).find('iframe').length > 0 || 862 $(mutation.target).is('iframe') || 863 $(mutation.target).hasClass('videoContent__iframe') || 864 $(mutation.target).hasClass('embed-responsive')) { 865 shouldReinit = true; 866 } 867 } 868 }); 869 870 if (shouldReinit) { 871 setTimeout(reinitializeVideoTracking, 500); 872 } 873 });
874 875 // Observe the document body for changes 876 var observeTarget = $('.videoContainer')[0] || document.body; 877 observer.observe(observeTarget, { 878 childList: true, 879 subtree: true, 880 attributes: true, 881 attributeFilter: ['aria-hidden', 'class', 'src'] 882 }); 883 884 // Initialize everything 885 setTimeout(function() { 886 initializeAllVideoTracking(); 887 setupPointerTracking(); 888 }, 100); 889 890 // Periodic reinitialization to catch any missed videos 891 setInterval(function() { 892 var currentVideoCount = Object.keys(videoTrackingState).length; 893 var actualVideoCount = $('iframe').filter(function() { 894 var src = $(this).attr('src'); 895 return src && (src.includes('youtube') || src.includes('vimeo') || src.includes('wistia') || src.includes('brightcove')); 896 }).length; 897 898 if (currentVideoCount !== actualVideoCount && actualVideoCount > 0) { 899 reinitializeVideoTracking(); 900 } 901 }, 3000); 902 903 // Add additional fallback - track any iframe clicks 904 $(document).on('click', 'iframe, .embed-responsive, .videoContent__iframe', function(e) { 905 var $iframe = $(this).is('iframe') ? $(this) : $(this).find('iframe').first(); 906 if ($iframe.length > 0) { 907 var src = $iframe.attr('src'); 908 if (src && (src.includes('youtube') || src.includes('vimeo') || src.includes('wistia') || src.includes('brightcove'))) { 909 var provider = 'unknown'; 910 try { 911 provider = new URL(src).hostname.replace('www.', ''); 912 } catch(e) { 913 provider = 'unknown'; 914 } 915 916 trackVideoEvent(provider, src, 'Video'); 917 } 918 } 919 }); 920 921 // Clean up on page unload 922 $(window).on('beforeunload', function() { 923 $(window).off('blur.videotrack'); 924 Object.keys(videoTrackingState).forEach(function(videoId) { 925 var videoState = videoTrackingState[videoId]; 926 videoState.element.off('mouseover.videotrack mouseout.videotrack click.videotrack'); 927 videoState.iframe.off('mouseover.videotrack mouseout.videotrack'); 928 }); 929 }); 930 931 // Debug function to check current state 932 window.debugVideoTracking = function() { 933 return { 934 trackedVideos: Object.keys(videoTrackingState).length, 935 currentActiveVideo: currentActiveVideo, 936 videoTrackingState: videoTrackingState 937 }; 938 }; 939 940 // Infinitely loop awards logos marquee 941 const root = document.documentElement; 942 const marqueeElementsDisplayed = getComputedStyle(root).getPropertyValue( 943 "--marquee-elements-displayed" 944 ); 945 const marqueeContent = document.querySelector("ul.bhc-awardsMarquee__content"); 946 947 if (marqueeContent) { 948 root.style.setProperty("--marquee-elements", marqueeContent.children.length); 949 950 951 for (let i = 0; i < marqueeElementsDisplayed; i++) { 952 marqueeContent.appendChild(marqueeContent.children[i].cloneNode(true)); 953 } 954 } 955});
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.