1(function ($) { 2 // Breakpoints 3 var phone = 480, 4 phablet = 768, 5 tablet = 992, 6 desktop = 1200; 7 8 function viewport() { 9 var e = window, 10 a = "inner"; 11 if (!("innerWidth" in window)) { 12 a = "client"; 13 e = document.documentElement || document.body; 14 } 15 return { width: e[a + "Width"], height: e[a + "Height"] }; 16 } 17 18 var vpWidth = viewport().width; // This should match the media query 19 20 //---------------------------------------------------------- 21 // HEADER SEARCH â Add/Remove 'active' class 22 //---------------------------------------------------------- 23 function reliasHeaderSearch() { 24 $(".search-text").click(function (e) { 25 if (window.innerWidth > 1170 || (window.innerWidth < 992 && window.innerWidth > 530)) { 26 e.preventDefault(); 27 $(this).parent(".search-container").toggleClass("js-active"); 28 $(this).toggleClass("js-active"); 29 $(this).siblings(".swiftype-searchpage-form").toggleClass("js-active"); 30 } 31 }); 32 33 $(document).click(function (event) { 34 var $target = $(event.target); 35 if (!$target.closest(".search-container").length && $(".search-text").hasClass("js-active")) { 36 $(".search-text").removeClass("js-active"); 37 $(".swiftype-searchpage-form").removeClass("js-active"); 38 } 39 }); 40 } 41 42 //---------------------------------------------------------- 43 // DETECT BROWSER 44 //---------------------------------------------------------- 45 function reliasBrowserType() { 46 if (navigator.userAgent.indexOf("Mac OS X") != -1) { 47 $("body").addClass("mac_browsers"); 48 } else { 49 $("body").addClass("windows_browser"); 50 } 51 } 52 53 //---------------------------------------------------------- 54 // SVG - svg tag cleanup 55 //---------------------------------------------------------- 56 function reliasSVG() { 57 if ($("img.svg_img").length) { 58 $("img.svg_img").each(function () { 59 var $img = $(this); 60 var imgID = $img.attr("id"); 61 var imgClass = $img.attr("class"); 62 var imgURL = $img.attr("src"); 63 64 $.get( 65 imgURL, 66 function (data) { 67 // Get the SVG tag, ignore the rest 68 var $svg = $(data).find("svg"); 69 70 // Add replaced image's ID to the new SVG 71 if (typeof imgID !== "undefined") { 72 $svg = $svg.attr("id", imgID); 73 } 74 // Add replaced image's classes to the new SVG 75 if (typeof imgClass !== "undefined") { 76 $svg = $svg.attr("class", imgClass + " replaced-svg"); 77 } 78 79 // Remove any invalid XML tags as per https://validator.w3.org 80 $svg = $svg.removeAttr("xmlns:a"); 81 82 // Check if the viewport is set, else we gonna set it if we can. 83 if (!$svg.attr("viewBox") && $svg.attr("height") && $svg.attr("width")) { 84 $svg.attr("viewBox", "0 0 " + $svg.attr("height") + " " + $svg.attr("width")); 85 } 86 87 // Replace image with new SVG 88 $img.replaceWith($svg); 89 }, 90 "xml", 91 ); 92 }); 93 } 94 } 95 96 function reliasFacetWPFilters() { 97 if ( 98 $(".post-type-archive-successstories").length || 99 $(".post-type-archive-resources").length || 100 $("body.blog").length || 101 $("body.archive.category").length || 102 $("body.page-template-webinar-page").length || 103 $("body.post-type-archive-events").length || 104 $("body.page-template-articles-reports-page").length 105 ) { 106 $(document).on("facetwp-loaded", function () { 107 // Show a reset button & filter selections if any facets are in use 108 var in_use = false;
109 // see if any facets are in use 110 $.each(FWP.facets, function (name, val) { 111 if (name !== "paged" && val.length > 0) { 112 in_use = true; 113 } 114 }); 115 116 // hide webinar selection type 117 if (in_use) { 118 if ($("body.page-template-webinar-page").length) { 119 let $webinarFacet = $('.facetwp-selections ul li[data-facet="resource_type"]'); 120 console.log($(".facetwp-selections li")); 121 $webinarFacet.css({ display: "none" }); 122 } 123 } 124 125 // true = show, false = hide 126 if ($("body.page-template-webinar-page").length) { 127 $(".facetwp-reset-btn, .archive-filter-selections").toggle(false); 128 $("div[data-name=resource_type] select").attr("disabled", "true"); 129 } else { 130 $(".facetwp-reset-btn, .archive-filter-selections").toggle(in_use); 131 } 132 133 /*// 'Disable' empty facets 134 $.each(FWP.settings.num_choices, function(key, val) { 135 var $parent = $('.facetwp-facet-' + key).closest('.facetwp-facet'); 136 (0 === val) ? $parent.addClass('js-disabled') : $parent.removeClass('js-disabled'); 137 });*/ 138 139 // Pagination scrolling 140 var ondemandQueryString = window.location.search; 141 var ondemandParams = new URLSearchParams(ondemandQueryString); 142 var pageParam = ondemandParams.get("_paged"); 143 144 if (!$("body.page-template-webinar-page").length) { 145 //$('html, body').animate({ scrollTop: 0 }, 500); 146 } else if (pageParam) { 147 // /resource/webinars on-demand section offset 148 var ondemandOffset = $("#ondemand-top").offset().top; 149 //$('html, body').animate({ scrollTop: ondemandOffset - 140 }, 500); 150 } 151 }); 152 153 // Loading icon whenever FacetWP is loading 154 // let $loading = $('.loading-gif-container'); 155 // $(document).on('facetwp-refresh', function() { 156 // if (window.location.pathname !== '/resource/webinar') { 157 // $loading.fadeIn(); 158 // } 159 // console.log(window.location.pathname); 160 // //$('.facetwp-template').animate({ opacity: 0 }, 500); 161 // }); 162 // 163 // $(document).on('facetwp-loaded', function() { 164 // if (window.location.pathname !== '/resource/webinar') { 165 // $loading.fadeOut(); 166 // } 167 // //$('.facetwp-template').animate({ opacity: 1 }, 500); 168 // 169 // }); 170 } 171 } 172 173 //---------------------------------------------------------- 174 // ANCHOR LINKS SMOOTH SCROLL - if a link is an anchor link/has value, 175 // smooth scroll to the section and add the hash to the URL when done scrolling 176 // .not() specifies what to ignore 177 //---------------------------------------------------------- 178 function reliasAnchorLinkSmoothScroll() { 179 if ( 180 $('.main-wrapper a[href*="#"]') 181 .not('[href="#"]') 182 .not('[href="#0"]') 183 .not(".relias-modal") 184 .not(".tab-link") // bootstrap tabs 185 .not(".collapsed").length 186 ) { 187 $('.main-wrapper a[href*="#"]') 188 .not('[href="#"]') 189 .not('[href="#0"]') 190 .not(".relias-modal") // bootstrap modals 191 .not(".tab-link") // boostrap tabs 192 .not(".accordion a") // bootstrap accordions 193 .not(".sticky-nav .nav-link") // handled by reliasStickyNavLinks() 194 .not("a.card-link.no-hash") 195 .on("click", function (event) { 196 // Make sure this.hash has a value before overriding default behavior 197 // Make sure this.href is equal to the current page, so smooth scrolling only works on same page links 198 if (this.hash !== "" && this.hostname == window.location.hostname) { 199 // Prevent default anchor click behavior 200 event.preventDefault(); 201 202 // Store hash 203 var hash = this.hash; 204 205 console.log("clicked..?"); 206 if ($(hash).length) { 207 $("html, body").animate( 208 { 209 scrollTop: $(hash).offset().top - 90, 210 }, 211 900, 212 "swing", 213 ); 214 } 215 } 216 }); 217 } 218 } 219 220 //---------------------------------------------------------- 221 // BOOTSTRAP TABS - controls open tabs and keeps them open on repeated click 222 //---------------------------------------------------------- 223 function reliasBootstrapTabs() { 224 if ($(".panel.panel-tabbed-content")) { 225 // Allow outer <li> element to become clickable 226 let $tabLinks = $(".tab-names a.tab-link"); 227 let $tabListItems = $(".tab-names li"); 228 let $tabs = $(".panel-tabbed-content ul.nav"); 229 $tabLinks.each(function () { 230 $(this).on("click", function (event) { 231 if ($(this).hasClass("active")) { 232 event.preventDefault(); 233 event.stopPropagation(); 234 } 235 }); 236 }); 237 // Add/remove active class on click 238 $tabListItems.each(function () { 239 let $tabs = $(".tab-pane"); 240 $(this).on("click", function () { 241 let $id = $(this).find("a.tab-link").attr("href"); 242 $tabListItems.removeClass("active"); 243 $(this).addClass("active"); 244 $tabs.each(function () { 245 let $hash = "#" + $(this).attr("id"); 246 if ($hash === $id) { 247 $("a.tab-link").removeClass("active"); 248 $(this).addClass("active"); 249 } else { 250 $(this).removeClass("active"); 251 } 252 }); 253 }); 254 }); 255 // Set width of tabs dynamically based on device width 256 let $tabsWidth = $tabs.width(); 257 if (vpWidth < phablet || $tabsWidth < 1000) { 258 $tabs.css("min-width", "1000px"); 259 $tabs.css("justify-content", "start"); 260 } 261 $(window).resize(function () { 262 if (vpWidth < phablet || $tabsWidth < 1000) { 263 $tabs.css("min-width", "1000px"); 264 $tabs.css("justify-content", "start"); 265 } else if (vpWidth > phablet && $tabsWidth < 100) { 266 $tabs.css("min-width", "unset"); 267 $tabs.css("justify-content", "center"); 268 } 269 }); 270 } 271 } 272 //---------------------------------------------------------- 273 // STICKY NAVS - handles fixed nav sidebars for sticky-nav.php panel c
273ontent 274 //---------------------------------------------------------- 275 function reliasStickyNav() { 276 if ($(".panel-sticky-nav").length) { 277 $(".panel-sticky-nav").each(function () { 278 var navArray = [], 279 $navPanels = $(".panel-sticky-nav"); 280 for (let i = 0; i < $navPanels.length; i++) { 281 navArray.push($("#side-" + i)); 282 } 283 284 function stickyNav(nav) { 285 // global (mobile and desktop) objects 286 var $sidebarHeight = nav.height(), 287 $sidebarWidth = nav.width(), 288 $sidebar = $("." + nav.attr("id") + "-anchor"), 289 $sidebarAnchor = $sidebar.offset().top, 290 $stickyNavContent = $sidebar.siblings($(".sticky-nav-content")), 291 $contentBottom = $("." + nav.attr("id") + "-anchor-bottom").offset().top, 292 $windowTop = $(window).scrollTop(); 293 294 // mobile sticky nav and dropdown arrow objects 295 let $arrowDropdown = nav.find($(".arrow-dropdown")), 296 $menuItems = nav.find($(".nav-item")), 297 $closedMenuItems = nav.find($(".nav-item:not(:first)")), 298 $firstMenuItem = nav.find($(".nav-item:first")), 299 $firstMenuItemLink = $firstMenuItem.find(".nav-link"); 300 301 // find first anchor and align it with the top of the sticky nav on mobile 302 let $stickyNavAnchors = $stickyNavContent.find(".anchor"); 303 if (vpWidth <= tablet) { 304 $stickyNavAnchors.eq(0).css({ top: "-" + $sidebarHeight }); 305 } else { 306 $stickyNavAnchors.eq(0).css({ top: "-100px" }); 307 } 308 309 // arrow dropdown click handler 310 if (vpWidth <= tablet) { 311 $arrowDropdown.unbind("click").on("click", function () { 312 $menuItems.each(function () { 313 let $this = $(this); 314 if ($this.hasClass("hide")) { 315 // if only the active item is shown 316 $this.toggleClass("hide"); // show all others 317 } else if (!$this.hasClass("hide") && !$this.children().hasClass("active")) { 318 $this.toggleClass("hide"); // hide the rest 319 } 320 }); 321 $arrowDropdown.toggleClass("flip"); 322 }); 323 } 324 325 // position the mobile dropdown arrow (appearance controlled below) 326 if (vpWidth <= phablet) { 327 $arrowDropdown.css({ right: "40px" }); 328 } else if (vpWidth >= phablet && vpWidth <= desktop) { 329 $arrowDropdown.css({ right: "72px" }); 330 } 331 332 // update the active menu item on scroll if menu is closed 333 if (vpWidth <= tablet) { 334 let $menuItemLinks = $menuItems.children(".nav-link"); 335 $menuItemLinks.each(function () { 336 let $this = $(this); 337 let $parent = $this.parent(); 338 let $nav = $("nav"); 339 if ($this.hasClass("active")) { 340 if ($parent.hasClass("hide")) { 341 $parent.toggleClass("hide"); 342 } 343 } else { 344 if (!$parent.hasClass("hide")) { 345 $parent.toggleClass("hide"); 346 if (!nav.hasClass("stick")) { 347 $menuItems.first().toggleClass("hide"); 348 } 349 } 350 } 351 }); 352 $arrowDropdown.removeClass("flip"); 353 } 354 355 // sticky nav behavior 356 if (vpWidth >= tablet) { 357 // screens > tablet (md) size 358 if ($windowTop + $sidebarHeight > $contentBottom - 100) { 359 nav.css({ top: ($windowTop + $sidebarHeight - $contentBottom + 36) * -1, width: $sidebarWidth }); 360 } else if ($windowTop + 80 > $sidebarAnchor) { 361 nav.addClass("stick").css({ top: 80, width: $sidebarWidth }); 362 } else { 363 nav.removeClass("stick").css({ top: "", width: "" }); 364 } 365 } else if (vpWidth <= tablet) { 366 // screens < tablet (md) size 367 if ($windowTop + $sidebarHeight > $contentBottom) {
368 nav.css({ top: ($windowTop + $sidebarHeight - $contentBottom + 100) * -1 }); 369 if ($arrowDropdown.is(":visible")) { 370 $arrowDropdown.hide(); 371 } 372 } else if ($windowTop > $sidebarAnchor - 88) { 373 // scrolling sticky nav onto screen 374 if (vpWidth <= phablet) { 375 nav.addClass("stick").css({ top: 88, width: "100%", backgroundColor: "#f4f4f2", right: 0, padding: "0 40px" }); 376 $stickyNavAnchors.eq(0).css({ height: $sidebarHeight + 30 + "px" }); 377 if (!$arrowDropdown.is(":visible")) { 378 $arrowDropdown.show(); 379 } 380 } else if (vpWidth >= phablet) { 381 nav.addClass("stick").css({ top: 88, width: "100%", backgroundColor: "#f4f4f2", right: 0, padding: "0 72px" }); 382 $stickyNavAnchors.eq(0).css({ height: $sidebarHeight + 30 + "px" }); 383 if (!$arrowDropdown.is(":visible")) { 384 $arrowDropdown.show(); 385 } 386 } 387 } else { 388 // scrolling sticky nav off of screen 389 nav.removeClass("stick").css({ top: "", width: "", padding: "0" }); 390 $stickyNavAnchors.eq(0).css({ height: "15px" }); 391 if ($arrowDropdown.is(":visible")) { 392 $arrowDropdown.hide(); 393 } 394 } 395 } else { 396 nav.removeClass("stick").css({ top: "", width: "" }); 397 } 398 } 399 400 // On scroll, stickyNav() runs and checks all .panel-sticky-nav anchors/offsets on the page 401 for (let i = 0; i < navArray.length; i++) { 402 stickyNav(navArray[i]); 403 } 404 }); 405 } 406 } 407 408 //---------------------------------------------------------- 409 // STICKY NAV SCROLLSPY - keeps .active on the nav item for the section the 410 // reader is actually looking at. 411 // 412 // Replaces Bootstrap scrollspy for the sticky-nav panel, which activated 413 // items too early for two reasons: it caches offsets at init, so 414 // late-loading images/posts/embeds leave them stale, and it measures the 415 // .anchor divs, which sit 100px above their heading. Everything here is 416 // measured off the section headings, live, on every pass. 417 //---------------------------------------------------------- 418 var STICKY_NAV_READ_BUFFER = 28, // px past the fixed chrome a heading must reach to count as read 419 STICKY_NAV_SCROLLED_OUT = 0.8, // scrolling down, hand over once this much of a section has left 420 STICKY_NAV_CLICK_GAP = 8; // where a clicked heading lands - must stay under the read buffer 421 422 var stickyNavActive = [], // active link index, per panel 423 stickyNavLastScroll = null, // previous scrollTop, for scroll direction 424 stickyNavTravel = 0, // travel accumulated since the last direction change 425 stickyNavDirection = "down"; // last confirmed scroll direction 426 427 // Direction from accumulated travel rather than a single delta: a trackpad 428 // can report 1-2px per event, and dropping those outright would leave a slow 429 // scroll up running on the scroll-down rule. 430 function reliasStickyNavTrack(delta) { 431 if (!delta) { 432 return; 433 } 434 if (delta < 0 !== stickyNavTravel < 0) { 435 stickyNavTravel = 0; // reversed - start counting this way instead 436 } 437 stickyNavTravel += delta; 438 439 if (stickyNavTravel <= -3) { 440 stickyNavDirection = "up"; 441 stickyNavTravel = 0; 442 } else if (stickyNavTravel >= 3) { 443 stickyNavDirection = "down"; 444 stickyNavTravel = 0; 445 } 446 } 447 448 // height of the fixed chrome covering the top of the page 449 function reliasStickyNavChrome($nav, forceStuck) { 450 var width = viewport().width, 451 $header = $("header.primary-header"), 452 chrome = width >= tablet ? 80 : 88; 453 454 if ($header.length) { 455 // Measured live off the header, so its real height wins over the 456 // fallbacks above. rect bottom rather than height picks up the offsets 457 // too - the 32px admin bar when logged in, or a header that has 458 // scrolled away when it isn't fixed (clamped to 0). 459 chrome = Math.max(0, $header[0].getBoundingClientRect().bottom); 460 } 461 // below tablet the sticky nav is fixed under the header and covers content 462 if (width < tablet && $nav.length) { 463 if ($nav.hasClass("stick")) { 464 chrome = Math.max(chrome, $nav[0].getBoundingClientRect().bottom); 465 } else if (forceStuck) { 466 chrome += $nav.outerHeight(); 467 } 468 } 469 return chrome; 470 } 471 472 // the section a nav link points at, and the heading to measure it by 473 function reliasStickyNavItem($link) { 474 var target = document.getElementById(($link.attr("href") || "").slice(1)), 475 $section = target ? $(target).closest(".sticky-section") : $(), 476 $heading = $section.find(".section-title").first(); 477 478 return { $section: $section, $heading: $heading.length ? $heading : $section }; 479 } 480
481 function reliasStickyNavSpy() { 482 if (!$(".panel-sticky-nav").length) { 483 return; 484 } 485 var $window = $(window), 486 scrollTop = $window.scrollTop(), 487 viewportHeight = $window.height(), 488 atPageBottom = scrollTop + viewportHeight >= $(document).height() - 2, 489 delta = stickyNavLastScroll === null ? 0 : scrollTop - stickyNavLastScroll; 490 491 reliasStickyNavTrack(delta); 492 stickyNavLastScroll = scrollTop; 493 494 $(".panel-sticky-nav").each(function (panelIndex) { 495 var $panel = $(this), 496 $links = $panel.find(".sticky-nav .nav-link[href^='#']"), 497 readLine = reliasStickyNavChrome($panel.find(".sticky-nav nav"), false) + STICKY_NAV_READ_BUFFER, 498 held = stickyNavActive[panelIndex], 499 handedOver = 0, // sections that have scrolled far enough out to pass the highlight on 500 current = 0, // last section whose heading is above the read line, i.e. the one being read 501 firstOnScreen = -1, // earliest heading currently on screen 502 index; 503 504 if (!$links.length) { 505 return; 506 } 507 508 $links.each(function (i) { 509 var item = reliasStickyNavItem($(this)); 510 if (!item.$section.length) { 511 return; 512 } 513 var sectionRect = item.$section[0].getBoundingClientRect(), 514 headingTop = item.$heading.length ? item.$heading[0].getBoundingClientRect().top : sectionRect.top; 515 516 if (sectionRect.top + sectionRect.height * STICKY_NAV_SCROLLED_OUT <= readLine) { 517 handedOver++; 518 } 519 if (headingTop <= readLine) { 520 current = i; 521 } 522 if (firstOnScreen < 0 && headingTop >= 0 && headingTop <= viewportHeight) { 523 firstOnScreen = i; 524 } 525 }); 526 527 if (stickyNavDirection === "up") { 528 // Coming back up, hand the highlight back a step as each earlier 529 // heading comes on screen. Releasing it the moment the lower heading 530 // drops past the read line instead would light up a section while 531 // only a sliver of its bottom shows. With no heading on screen we are 532 // mid-way through a long section, so that section keeps it. 533 index = firstOnScreen >= 0 ? firstOnScreen : current; 534 if (typeof held === "number") { 535 index = Math.min(index, held); // scrolling up never moves the highlight forward 536 } 537 } else { 538 // Going down, a section keeps the highlight until STICKY_NAV_SCROLLED_OUT 539 // of it has passed the read line. Section extents are in document 540 // order, so the ones handed over are always a leading run - their 541 // count is the section now being read. 542 index = Math.min(handedOver, $links.length - 1); 543 } 544 545 if (atPageBottom) { 546 index = $links.length - 1; // a short final section never reaches the read line 547 } 548 if (index < 0) { 549 index = 0; // above the panel - keep the first item marked so the collapsed mobile nav has one 550 } 551 552 stickyNavActive[panelIndex] = index; 553 $links.removeClass("active"); 554 $links.eq(index).addClass("active"); 555 }); 556 } 557 558 // Scroll a clicked sticky nav item's heading to just below the fixed chrome, 559 // so the landing position agrees with where the spy reads the active item 560 function reliasStickyNavLinks() { 561 $(".panel-sticky-nav .sticky-nav") 562 .find(".nav-link[href^='#']") 563 .on("click", function (event) { 564 var $link = $(this), 565 $heading = reliasStickyNavItem($link).$heading; 566 567 if (!$heading.length) { 568 return; 569 } 570 event.preventDefault(); 571 572 var $nav = $link.closest(".panel-sticky-nav").find(".sticky-nav nav"), 573 top = $heading.offset().top - reliasStickyNavChrome($nav, true) - STICKY_NAV_CLICK_GAP; 574 575 $("html, body") 576 .stop(true) 577 .animate({ scrollTop: Math.max(top, 0) }, 600, "swing", reliasStickyNavSpy); 578 }); 579 } 580 581 //---------------------------------------------------------- 582 // SCROLLSPY - Adds .active class to nav-items as page scrolls 583 //---------------------------------------------------------- 584 if ($(".sidebar-menu").length) { 585 // Legacy 2019 topic template sidebar only - the sticky-nav panel is
586 // handled by reliasStickyNavSpy() above 587 $("body").scrollspy({ target: ".sidebar-menu", offset: 1 }); 588 } 589 590 //---------------------------------------------------------- 591 // TABLE HEIGHTS - adjusts heights of parallel rows to match each other in Pricing Tables panel 592 //---------------------------------------------------------- 593 function reliasTableHeights() { 594 if ($(".panel.panel-pricing-tables.adjusted .competitors-layout").length) { 595 let $columns = $(".competitors-layout .table-column"); 596 let firstColumnRows = []; 597 $columns.each(function (index) { 598 let $rows = $(this).find(".column-row"); 599 $rows.each(function (index2) { 600 // Get heights of first column rows 601 if (index == 0) { 602 firstColumnRows.push($(this).outerHeight()); 603 // Then match heights against respective columns in subsequent rows (index != 0) 604 } else if ($(this).attr("id") == "column-row-" + index2 + "-" + index) { 605 let targetHeight = firstColumnRows[index2]; 606 let padding = (targetHeight - 24) / 2; 607 $(this).css("padding", padding); 608 } 609 }); 610 }); 611 } 612 } 613 614 //---------------------------------------------------------- 615 // ACCORDIONS - 616 // (commented out) Opens the first collapsed item for each accordion panel 617 // If radio button options are used, provides functionality for checking on and off 618 //---------------------------------------------------------- 619 function reliasAccordion() { 620 if ($(".panel-accordion").length) { 621 // open first accordion by default on page load, only if an image is present 622 $(".panel-accordion").each(function () { 623 var $this = $(this); 624 $this.find(".card").each(function (i) { 625 $this; // parent li 626 this; // child li 627 if (i === 0 && $(this).find(".accordion-img")) {
628 // Will be done to first element. 629 $(this).find(".collapse").collapse("show"); 630 } 631 }); 632 // check first radio button, if it exists 633 if ($this.find(".form-control input").length) { 634 $this.find(".form-control input").each(function (a) { 635 if (a === 0) { 636 $(this).prop("checked", true); 637 } 638 }); 639 } 640 }); 641 $(".form-control input").each(function () { 642 $(this).on("click", function () { 643 if (!$(this).hasClass("collapsed")) { 644 $(this).prop("checked", false); 645 } 646 }); 647 }); 648 649 if (vpWidth >= phablet) { 650 // dynamic image functionality 651 // changes image in a set container as cells are opened/closed 652 let $accordions = $(".panel-accordion.external-images .accordion"); 653 $accordions.each(function () { 654 let $cards = $(".card .accordion-btn"); 655 let $images = $(".accordion-outer-img"); 656 $cards.each(function (index) { 657 $(this).on("click", function () { 658 $images.addClass("d-none"); 659 $images.eq(index).toggleClass("d-none"); 660 }); 661 }); 662 }); 663 } 664 } 665 } 666 667 //----------------------------------------------------------------------- 668 // QUOTE BAR - 669 // Resizes background image height to fit in case quote body is too long 670 //----------------------------------------------------------------------- 671 function reliasQuoteBarResizing() { 672 let $quoteBars = $(".panel.panel-quote-bar .panel-container.background-image"); 673 if ($quoteBars.length) { 674 $quoteBars.each(function () { 675 let $panelContainer = $(this); 676 let $quoteBody = $panelContainer.find(".quote-body"); 677 let $quoteHeight = $quoteBody.height() + 144; 678 $panelContainer.css({ height: $quoteHeight + 144 }); 679 }); 680 } 681 } 682 683 // Also adjust whenever page is resized 684 $(window).on("resize", function () { 685 reliasQuoteBarResizing(); 686 }); 687 688 //----------------------------------------------------------------------- 689 // QUOTE BAR VIEWPORT OBSERVER - 690 // Triggers reliasTableHeights() when quote bar enters viewport 691 //----------------------------------------------------------------------- 692 function reliasQuoteBarViewportObserver() { 693 let $quoteBars = $(".panel.panel-quote-bar .panel-container.background-image"); 694 695 if ($quoteBars.length && "IntersectionObserver" in window) { 696 const observerOptions = { 697 root: null, 698 rootMargin: "0px", 699 threshold: 0.1, // Trigger when 10% of element is visible 700 }; 701 702 const observer = new IntersectionObserver(function (entries, observer) { 703 entries.forEach(function (entry) { 704 if (entry.isIntersecting) { 705 // Element is in viewport - adjust heights 706 reliasQuoteBarResizing(); 707 708 // Unobserve after first trigger to avoid repeated calls 709 observer.unobserve(entry.target); 710 } 711 }); 712 }, observerOptions); 713 714 // Observe each quote bar element 715 $quoteBars.each(function () { 716 observer.observe(this); 717 }); 718 } else if ($quoteBars.length) { 719 // Fallback for browsers without IntersectionObserver support 720 $(window).on("scroll", function () { 721 $quoteBars.each(function () { 722 let $this = $(this); 723 724 // Skip if already processed 725 if ($this.data("quote-bar-processed")) { 726 return; 727 } 728 729 let elementTop = $this.offset().top; 730 let elementBottom = elementTop + $this.outerHeight(); 731 let viewportTop = $(window).scrollTop(); 732 let viewportBottom = viewportTop + $(window).height(); 733 734 if (elementBottom > viewportTop && elementTop < viewportBottom) { 735 reliasQuoteBarResizing(); 736 737 // Mark as processed to avoid repeated calls 738 $this.data("quote-bar-processed", true); 739 } 740 }); 741 }); 742 } 743 } 744 745 function reliasFlickityResize() { 746 // Temporary Fix: Trigger a window resize to fix the viewport of Flickity Quote Carousel
747 if ($(".panel-quote-carousel").length) { 748 setTimeout(function () { 749 // $(window).trigger('resize'); 750 $(".flickity-carousel").flickity("resize"); 751 }, 1000); 752 } 753 } 754 755 // Reload page if certain panels are on screen, so that resizing doesn't cause issues 756 $(window).resize(function () { 757 if ($(".panel.panel-sticky-nav nav").hasClass("stick")) { 758 location.reload(); 759 } 760 }); 761 762 function reliasModals() { 763 let $modalLink = $("a.relias-modal"); 764 if ($modalLink.length) { 765 // On click 766 $modalLink.on("click", function (e) { 767 e.preventDefault(); 768 let $target = $(this).data("val"); 769 $($target).modal("show"); 770 }); 771 772 // Remove focus 773 $modalLink.on("hidden.bs.modal", function () { 774 let $target = "#" + $(this).data("val"); 775 $target.blur(); 776 }); 777 } 778 } 779 780 function reliasBootstrapMenu() { 781 // jQuery objects 782 // desktop 783 let $mainWrapper = $(".main-wrapper-inn"), 784 $reliasNav = $(".relias-nav-container"), 785 $mainMenu = $(".relias-desktop-menu"), 786 $mainItems = $(".relias-desktop-menu .menu-item-has-children"), 787 $mainItemsLinks = $(".relias-desktop-menu > li > a"), 788 $mainItemsDropdowns = $(".relias-desktop-menu .menu-item-has-children"); 789 // mobile 790 let $mobileMenuParent = $(".relias-nav-buttons"), // Bootstrap adds .show to parent, not button 791 $mobileButton = $("#reliasMobileButton"), 792 $mobileMenu = $(".relias-mobile-menu.dropdown-menu"), 793 $mobileItems = $(".relias-mobile-menu .menu-item-has-children .dropdown-toggle"), 794 $subMenus = $(".relias-mobile-menu .menu-item-has-children a.dropdown-toggle"), 795 $mobileDemoButton = $(".mobile-demo-button"); 796 797 // box shadow toggling 798 $mainItemsDropdowns.each(function () { 799 $(this).on("shown.bs.dropdown", function () { 800 $reliasNav.addClass("hide-before"); 801 }); 802 $(this).on("hidden.bs.dropdown", function () { 803 $reliasNav.removeClass("hide-before"); 804 }); 805 }); 806 807 // hamburger button functionality 808 if ($mobileButton) { 809 $mobileButton.on("click", function () { 810 $(this).toggleClass("is-active"); 811 if (!$(this).hasClass("is-active")) { 812 // hide back shade 813 $(".back_shad").fadeOut(300); 814 // close all 2nd level submenus 815 $(".dropdown-menu.mobile-titled").each(function () { 816 $(this).removeClass("show"); 817 }); 818 } else { 819 // show back shade 820 $(".back_shad").fadeIn(300); 821 } 822 }); 823 $mobileMenu.parent().on("shown.bs.dropdown", function () { 824 $mobileDemoButton.removeClass("d-none"); 825 }); 826 $mobileMenu.parent().on("hidden.bs.dropdown", function () { 827 $mobileDemoButton.addClass("d-none"); 828 }); 829 } 830 831 // add overflow-y scroll for dropdown menu when submenus are open (not needed at first level) 832 $subMenus.parent().each(function () { 833 $(this).children("a").removeAttr("href"); // remove href so that FacetWP doesn't trigger a refresh due to hash 834 $(this).on("click", function () { 835 $(this).find(".mobile-titled").trigger("appear"); 836 }); 837 }); 838 $subMenus.siblings().on("appear", function () { 839 if ($(this).hasClass("show")) { 840 $mobileMenu.css("overflow-y", "scroll"); 841 console.log("show!"); 842 } else { 843 $mobileMenu.css("overflow-y", "hidden"); 844 console.log("hide!"); 845 } 846 }); 847 848 // keep menu and submenus from closing on clicks other than links 849 $mobileMenu.on("click", function (event) { 850 event.stopPropagation(); 851 //event.preventDefault(); 852 }); 853 854 // submenu functionality 855 $mobileItems.each(function (index) { 856 // bootstrap default event propagation override (keeps menu from closing on menu item click) 857 $(this) 858 .on("click") 859 .click(function (event) { 860 //event.stopPropagation(); 861 });
862 // hide/show submenu content 863 $(this).on("click", function (index) { 864 $(this).siblings(".dropdown-menu").toggleClass("show"); 865 }); 866 // create submenu title buttons 867 let $title = $(this).find('p[itemprop="name"]').html(); 868 if (!$(this).siblings(".dropdown-menu").find(".title").length) { 869 $(this) 870 .siblings(".dropdown-menu") 871 .prepend('<div id="button-' + $mobileItems.index(this) + '" class="title"><span>v</span>' + $title + "</div>"); 872 } 873 // create click handler functionality for submenu title buttons 874 let $buttons = $("#button-" + $mobileItems.index(this)); 875 $buttons.each(function () { 876 $(this).on("click", function () { 877 $(this).parent().removeClass("show"); 878 }); 879 }); 880 }); 881 882 // adjust top value for each third-level submenu on mobile so that they all appear in the same location when opened 883 let $submenus = $(".dropdown-menu.mobile-titled"); 884 let top = 0; 885 $submenus.each(function () { 886 $(this).css("top", top); 887 top = top - 62; 888 }); 889 890 // reusable function that resets all menu elements to closed/inactive states 891 function menuReset() { 892 // check if main menu is visible before resetting 893 if ($mainMenu) { 894 $mainItems.each(function () { 895 if ($(this).hasClass("show")) { 896 $(this).removeClass("show"); 897 $(this).find(".dropdown-menu").removeClass("show"); 898 } 899 }); 900 } 901 // reset aria-expanded=true states 902 $mainItemsLinks.each(function () { 903 $(this).attr("aria-expanded", "false"); 904 }); 905 // check if mobile menu is visible before resetting 906 if ($mobileButton) { 907 // reset visibility 908 mobileMenuReset(); 909 // reset hamburger button and submenu states 910 $mobileMenuParent.on("shown.bs.dropdown", function () { 911 $mobileButton.addClass("is-active"); 912 }); 913 // reset submenu and description states 914 $mobileMenuParent.on("hidden.bs.dropdown", function () { 915 mobileMenuReset(); 916 }); 917 } 918 } 919 920 function mobileMenuReset() { 921 $mobileMenuParent.removeClass("show"); 922 $mobileMenu.removeClass("show"); 923 $mobileButton.removeClass("is-active"); 924 $mobileDemoButton.addClass("d-none"); 925 $subMenus.each(function () { 926 $(this).removeClass("show"); 927 }); 928 $(".dropdown-menu.mobile-titled").each(function () { 929 $(this).removeClass("show"); 930 }); 931 $mobileItems.each(function () { 932 $(this).siblings(".submenu-description").removeClass("hide"); 933 $(this).find(".plus").removeClass("rotate"); 934 }); 935 $(".back_shad").fadeOut(300); 936 } 937 938 // reset objects on window resize 939 $(window).resize(function () { 940 menuReset(); 941 mobileMenuReset(); 942 // reset search box, if open 943 if ($(".search-text").hasClass("js-active")) { 944 $(".search-text").removeClass("js-active"); 945 $(".swiftype-searchpage-form").removeClass("js-active"); 946 } 947 }); 948 } 949 950 // Handle iframe postmessages and reset their heights to account for progressive profiling 951 function reliasResizeIframes() { 952 let $demoIframe = $("#demoForm"); 953 if ($("#demoForm").length) { 954 let height; 955 window.addEventListener("message", function (event) { 956 height = event.data; 957 $demoIframe.css({ height: height }); 958 }); 959 } 960 } 961 962 // Add href attributes to FacetWP pagination links for SEO value 963 function reliasFacetWPPaginationHrefs() { 964 let $pager = $(".facetwp-pager"); 965 if ($pager) { 966 document.addEventListener("facetwp-loaded", function () { 967 let $pages = $(".facetwp-page"); 968 $pages.on("click", function (event) { 969 event.preventDefault(); 970 }); 971 $pages.each(function () { 972 if (!$(this).hasClass("dots")) { 973 let $url = window.location.href; 974 let $dataPage = $(this).attr("data-page"); 975 // If not on page 1 976 if ($url.includes("paged")) { 977 // if leading back to page 1, add no "?_param=" 978 if ($dataPage == 1) { 979 $url = location.protocol + "//" + location.host + location.pathname; 980 // otherwise, add the param and number 981 } else { 982 $url = location.protocol + "//" + location.host + location.pathname + "?_paged=" + $dataPage; 983 } 984 $(this).attr("href", $url); 985 // If page 1, add '?_paged=' param to non-first pages 986 } else { 987 if ($(this).hasClass("first")) { 988 $(this).attr("href", $url); 989 } else { 990 let $pagedUrl = $url + "?_paged=" + $dataPage; 991 $(this).attr("href", $pagedUrl); 992 } 993 } 994 } 995 }); 996 }); 997 } 998 } 999 1000 // On document ready 1001 $(document).ready(function () { 1002 reliasBootstrapMenu(); 1003 reliasBrowserType(); 1004 reliasSVG(); 1005 reliasAnchorLinkSmoothScroll(); 1006 reliasFlickityResize(); 1007 reliasModals(); 1008 reliasAccordion(); 1009 reliasFacetWPFilters(); 1010 reliasTableHeights(); 1011 reliasBootstrapTabs(); 1012 reliasQuoteBarResizing(); 1013 reliasFacetWPPaginationHrefs(); 1014 reliasResizeIframes(); 1015 reliasQuoteBarViewportObserver(); // Initialize viewport observer for quote bars; 1016 reliasStickyNavLinks();
1017 reliasStickyNavSpy(); 1018 }); 1019 1020 // On window scroll 1021 $(window).scroll(function () { 1022 reliasStickyNavSpy(); // before reliasStickyNav() - the mobile dropdown reads .active 1023 reliasStickyNav(); 1024 }); 1025 1026 // Re-measure once late-loading content has settled, and on resize 1027 $(window).on("load resize", function () { 1028 reliasStickyNavSpy(); 1029 }); 1030 1031 // Load anchors at offset from top nav 1032 if (window.location.hash) { 1033 // set scroll position to 0 1034 scroll(0, 0); 1035 // smooth scroll to the anchor id 1036 setTimeout(() => { 1037 $("html, body").animate( 1038 { 1039 scrollTop: $(window.location.hash + "-hash").offset().top - 90, 1040 }, 1041 1000, 1042 "swing", 1043 ); 1044 }, 2000); 1045 } 1046})(jQuery);
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.