1jQuery.noConflict(); 2 3(function($) { 4 $(function() { 5 // GF phone fields: drop the prefilled placeholder 6 $('.ginput_container_phone input').removeAttr('placeholder'); 7 8 // login form error text 9 if ($('.login-form .wppb-error, .portal__login .wppb-error').length > 0) { 10 $('.login-form .wppb-error, .portal__login .wppb-error').html('<strong>ERROR</strong>: Invalid Code.'); 11 } 12 13 // GravityView edit mode: pull the page's own form widget 14 const params = new URLSearchParams(window.location.search); 15 if (params.get('gvid') && params.get('edit')) { 16 $('.portal .elementor-widget-wp-widget-gform_widget .gform_wrapper').remove(); 17 } 18 19 // hide an empty GravityView table 20 const $gvTable = $(".gv-table-view"); 21 if ($gvTable.length > 0 && $gvTable.find('.gv-no-results').length > 0) { 22 $gvTable.hide(); 23 } 24 25 // portal sidebar: drawer below 768px, sub-menus toggle in place 26 const $portalNav = $('[data-portal-nav]'); 27 if ($portalNav.length) { 28 const $pToggle = $portalNav.find('.portal-nav__toggle'); 29 const $pClose = $portalNav.find('.portal-nav__close'); 30 31 function setPortalNav(open) { 32 $portalNav.toggleClass('portal-nav--open', open); 33 $('body').toggleClass('portal-nav-open', open); 34 $pToggle.attr('aria-expanded', open ? 'true' : 'false'); 35 (open ? $pClose : $pToggle).trigger('focus'); 36 } 37 38 $pToggle.on('click', function() { setPortalNav(true); }); 39 $pClose.add($portalNav.find('.portal-nav__scrim')).on('click', function() { setPortalNav(false); }); 40 $(document).on('keydown', function(e) { 41 if (e.key === 'Escape' && $portalNav.hasClass('portal-nav--open')) { 42 setPortalNav(false); 43 } 44 }); 45 46 // current page's branch opens on load, the rest start closed 47 $portalNav.find('.portal-nav__menu .menu-item-has-children').each(function() { 48 const $li = $(this); 49 const open = $li.is('.current-menu-item, .current-menu-parent, .current-menu-ancestor, .current_page_ancestor'); 50 $li.toggleClass('is-open', open); 51 $('<button type="button" class="portal-nav__submenu-toggle" aria-label="Show sub-pages"></button>') 52 .attr('aria-expanded', open ? 'true' : 'false') 53 .insertAfter($li.children('a').first()); 54 }); 55 56 $portalNav.on('click', '.portal-nav__submenu-toggle', function() { 57 const $li = $(this).closest('li'); 58 const open = !$li.hasClass('is-open'); 59 $li.toggleClass('is-open', open); 60 $(this).attr('aria-expanded', open ? 'true' : 'false'); 61 }); 62 } 63 64 // required field legend 65 const requiredLegend = ` 66 <div class="gform_require_sign"> 67 <p class="gform_required_legend"> 68 "<span class="gfield_required gfield_required_asterisk">*</span>" indicates required fields 69 </p> 70 </div> 71 `; 72 $(requiredLegend).insertAfter("#gform_wrapper_67 .gf_page_steps, #gform_wrapper_247 .gf_page_steps"); 73 74 const $navToggle = $('.site-header__toggle'); 75 const $navClose = $('.primary-navbar__close'); 76 77 // aria-expanded tracks whether #primary-navbar is open 78 function setNavOpen(open) { 79 $('body').toggleClass('nav-open-overlay', open); 80 $navToggle.attr('aria-expanded', open ? 'true' : 'false'); 81 // focus follows the panel or the next Tab lands at the top of the page 82 (open ? $navClose : $navToggle).trigger('focus'); 83 } 84 85 $navToggle.on('click', function() { 86 setNavOpen(true); 87 }); 88 89 // bound to the button not the inner span, keyboard clicks do not reach descendants 90 $navClose.on('click', function() { 91 setNavOpen(false); 92 }); 93 94 $(document).on('keydown', function(e) { 95 if (e.key === 'Escape' && $('body').hasClass('nav-open-overlay')) { 96 setNavOpen(false); 97 } 98 }); 99 100 $(document).on("click", ".primary-navbar__list li.menu-item-has-children > a", function (e) { 101 const link = $(this); 102 const submenu = link.next(".sub-menu"); 103 104 const linkWidth = link.outerWidth(); 105 const iconZoneWidth = 30; // clickable area width (px) 106 const clickX = e.offsetX; 107 108 // clicks in the icon zone at the right edge toggle the submenu 109 if (clickX > linkWidth - iconZoneWidth) { 110 e.preventDefault(); 111 112 if (submenu.is(":visible")) { 113 link.removeClass("open"); 114 submenu.slideUp(200); 115 } else { 116 $(".primary-navbar__list li.menu-item-has-children > a").removeClass("open"); 117 $(".primary-navbar__list .sub-menu").slideUp(200); 118 119 link.addClass("open"); 120 submenu.slideDown(200); 121 } 122 } 123 }); 124 125 // feature list reveal 126 127 const $features = $('.feature-list'); 128 129 if ($features.length && 'IntersectionObserver' in window) { 130 $features.addClass('js-reveal'); 131 132 const reveal = new IntersectionObserver(function (entries) {
133 entries.forEach(function (entry) { 134 if (entry.isIntersecting) { 135 entry.target.classList.add('is-inview'); 136 reveal.unobserve(entry.target); 137 } 138 }); 139 }, { threshold: 0.2, rootMargin: '0px 0px -10% 0px' }); 140 141 $features.find('.feature-list__item').each(function () { 142 reveal.observe(this); 143 }); 144 } 145 146 // archive filter: a real <select> that submits on change 147 148 $(document).on('change', 'select[data-autosubmit]', function () { 149 this.form.submit(); 150 }); 151// empty selects stay out of the URL 152$(document).on('submit', 'form:has(select[data-autosubmit])', function () { 153 $(this).find('select').each(function () { if (this.value === '') { this.disabled = true; } }); 154}); 155 156 // sticky header 157 158 const $header = $('.site-header'); 159 160 // two thresholds so the colour swap does not flicker around one line 161 let sticky = false; 162 function checkSticky() { 163 const y = $(window).scrollTop(); 164 if (!sticky && y > 24) { sticky = true; } 165 else if (sticky && y < 4) { sticky = false; } 166 $header.toggleClass('is-sticky', sticky); 167 // also on body, the fly-out panel is a sibling and reads its vars from there 168 $('body').toggleClass('is-header-sticky', sticky); 169 } 170 171 checkSticky(); 172 $(window).on('scroll load resize', checkSticky); 173 174 }); 175})(jQuery); 176// section nav: current tab scrolled into view, the edge with more tabs fades 177document.querySelectorAll('[data-section-nav]').forEach(function (scroller) { 178 var current = scroller.querySelector('.is-current'); 179 var update = function () { 180 scroller.classList.toggle('is-overflowing', scroller.scrollWidth > scroller.clientWidth + 1); 181 scroller.classList.toggle('is-end', scroller.scrollLeft + scroller.clientWidth >= scroller.scrollWidth - 2); 182 }; 183 if (current && scroller.scrollWidth > scroller.clientWidth) { 184 scroller.scrollLeft = current.offsetLeft - (scroller.clientWidth - current.offsetWidth) / 2; 185 } 186 update(); 187 scroller.addEventListener('scroll', update, { passive: true }); 188 window.addEventListener('resize', update); 189}); 190 191// carousel: the track is a scroll-snap strip, buttons scroll it one slide 192document.querySelectorAll('[data-carousel]').forEach(function (carousel) { 193 var track = carousel.querySelector('.carousel__track'); 194 var current = carousel.querySelector('[data-carousel-current]'); 195 var prev = carousel.querySelector('[data-carousel-prev]'); 196 var next = carousel.querySelector('[data-carousel-next]'); 197 if (!track) { return; } 198 199 var slides = Array.prototype.slice.call(track.children); 200 var index = function () { 201 var x = track.scrollLeft, best = 0; 202 slides.forEach(function (el, i) { if (Math.abs(el.offsetLeft - x) < Math.abs(slides[best].offsetLeft - x)) { best = i; } }); 203 return best; 204 }; 205 var go = function (i) { 206 i = Math.max(0, Math.min(slides.length - 1, i)); 207 track.scrollTo({ left: slides[i].offsetLeft, behavior: 'smooth' }); 208 }; 209 210 if (prev) { prev.addEventListener('click', function () { go(index() - 1); }); } 211 if (next) { next.addEventListener('click', function () { go(index() + 1); }); } 212 track.addEventListener('scroll', function () { 213 if (current) { current.textContent = index() + 1; } 214 }, { passive: true }); 215}); 216 217// elementor testimonial carousel: the theme shows the overflow, so loop mode needs more clones than the one-per-view default 218jQuery(window).on('elementor/frontend/init', function () { 219 elementorFrontend.hooks.addAction('frontend/element_ready/testimonial-carousel.default', function ($el) { 220 var container = $el.find('.elementor-main-swiper')[0]; 221 var tries = 0; 222 if (!container) { return; } 223 224 (function wait() { 225 var swiper = container.swiper; 226 if (!swiper) { if (tries++ < 100) { setTimeout(wait, 50); } return; } 227 if (!swiper.params.loop) { return; } 228 229 swiper.params.loopAdditionalSlides = 3; 230 swiper.loopDestroy(); 231 swiper.loopCreate(); 232 swiper.update(); 233 swiper.slideToLoop(0, 0); 234 })(); 235 }); 236}); 237 238// portal login and content handlers 239jQuery(function ($) { 240 // single-password login, the username doubles as the password 241 $('.page-template-portal-login .login-username input, .page-template-vip-portal-alt .login-username input').on('change', function () { 242 $(this).closest('form').find('.login-password input').val($(this).val()); 243 }); 244
245 var cb = $('form.user-already-submitted #input_234_13_1'); 246 if (cb.length && cb.val() === '1') { 247 cb.prop('checked', true); 248 } 249 250 $('#generate-email').on('click', function () { 251 $('#vip-invite-email-content').toggle(500); 252 }); 253}); 254
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.