1// Scripts specifically for the homepage 2(function ($) { 3 // Homepage-specific global variables 4 var enablePreloader = false; 5 var preloaderDuration = 3800; 6 7 // Document Ready = DOM is ready but content is not necessarily loaded 8 $(function () { 9 // Handle preloader 10 if (enablePreloader && $("#preloader").exists() && !localStorage.getItem("preloaderFinished")) { 11 startPreloader(); 12 } else { 13 // Preloader not enabled; remove the element, if it exists 14 $("#preloader").remove(); 15 } 16 17 $(".connect-form .form-container h2").on("click", function () { 18 $(this).closest(".form-container").toggleClass("is-active"); 19 }); 20 21 function scrollToFooter() { 22 let $footer = $(".footer"); 23 24 if ($footer.length) { 25 animateScroll($footer.offset().top - getScrollAdjustValue(), 900); 26 } 27 } 28 29 $(".connect-circle, .feedback-circle").on("click", function () { 30 scrollToFooter(); 31 }); 32 33 $(".connect-circle, .feedback-circle").on("keydown", function (event) { 34 if (event.key === "Enter" || event.key === " ") { 35 event.preventDefault(); 36 $(this).trigger("click"); 37 } 38 }); 39 40 let footerFormFields = document.querySelectorAll(".footer .gform_fields .gfield, .footer .gform_footer"); 41 let footerFormFieldsContainer = document.querySelector(".footer .gform_fields"); 42 43 if (footerFormFields.length && footerFormFieldsContainer && typeof anime === "function" && typeof IntersectionObserver === "function") { 44 anime.set(footerFormFields, { 45 opacity: 0, 46 translateY: 30, 47 }); 48 49 let footerFormObserver = new IntersectionObserver(function (entries, observer) { 50 entries.forEach(function (entry) { 51 if (entry.isIntersecting) { 52 anime({ 53 targets: footerFormFields, 54 opacity: [0, 1], 55 translateY: [30, 0], 56 duration: 700, 57 easing: "easeOutSine", 58 delay: anime.stagger(120), 59 }); 60 61 observer.unobserve(entry.target); 62 } 63 }); 64 }, { 65 threshold: 0.25, 66 }); 67 68 footerFormObserver.observe(footerFormFieldsContainer); 69 } 70 71 // Begins preloader functionality and animations 72 function startPreloader() { 73 $("#preloader, .preloader-part").addActive(); 74 75 anime({ 76 targets: ".preloader-part-right p", 77 opacity: [0, 1], 78 translateY: [60, 0], 79 duration: 1200, 80 loop: false, 81 easing: "easeOutSine", 82 delay: anime.stagger(500, { start: 700 }), 83 }); 84 85 setTimeout(finishPreloader, preloaderDuration); 86 } 87 88 // Begins preloader exit; ensures it does not reappear in the session 89 function finishPreloader() { 90 // Set localStorage variable for this session 91 localStorage.setItem("preloaderFinished", 1); 92 93 // Begin preloader exit 94 $("#preloader").addClass("preloader-remove"); 95 96 setTimeout(function () { 97 // At this point, preloader fade-out must be complete 98 $("#preloader").remove(); 99 }, 1500); 100 } 101 }); 102 103 $(window).on("load", function () { 104 startHomeAnimations(); 105 }); 106 107 anime( { 108 targets: '.hero-title-3 span', 109 opacity: [0, 1], 110 translateY: [0, 0], 111 duration: 1500, 112 easing: 'easeOutSine', 113 delay: anime.stagger( 150, { start: 1500 } ) 114 } ); 115 116 document.querySelectorAll(".intro-title-reveal").forEach(introTitle => { 117 let introTitleObserver = new IntersectionObserver(function(entries, observer) { 118 entries.forEach(entry => { 119 if (entry.isIntersecting) { 120 anime({ 121 targets: entry.target.querySelectorAll("span"), 122 opacity: [0, 1], 123 translateY: [0, 0], 124 duration: 1500, 125 easing: "easeOutSine", 126 delay: anime.stagger(150, { start: 500 }), 127 }); 128 129 observer.unobserve(entry.target); 130 } 131 }); 132 }, { 133 threshold: 0.5 134 }); 135 136 introTitleObserver.observe(introTitle); 137 }); 138 139 // Counter JS 140 let counters = document.querySelectorAll(".js-counter"); 141 142 let options = { 143 threshold: 0.5 144 }; 145 146 let observer = new IntersectionObserver(function(entries, observer) { 147 entries.forEach(entry => { 148 if (entry.isIntersecting) { 149 let item = entry.target; 150 let endNumber = parseFloat(item.dataset.number); 151 let duration = 1500; 152 let startTime = null; 153 let decimalPlaces = (item.dataset.number.split(".")[1] || "").length; 154 155 let animateCounter = timestamp => { 156 if (!startTime) { 157 startTime = timestamp; 158 } 159 160 let progress = Math.min((timestamp - startTime) / duration, 1);
161 let currentNumber = endNumber * progress; 162 item.textContent = decimalPlaces ? currentNumber.toFixed(decimalPlaces) : Math.floor(currentNumber); 163 164 if (progress < 1) { 165 requestAnimationFrame(animateCounter); 166 } else { 167 item.textContent = decimalPlaces ? endNumber.toFixed(decimalPlaces) : endNumber; 168 } 169 }; 170 171 requestAnimationFrame(animateCounter); 172 173 observer.unobserve(item); 174 } 175 }); 176 }, options); 177 178 // Observe each counter 179 counters.forEach(counter => { 180 observer.observe(counter); 181 }); 182 183 function startHomeAnimations() { 184 // If not on the homepage or on mobile, leave this function 185 // if (isMobileScreen()) { 186 // Remove opacity0 to reveal hidden elements 187 // $(".opacity0").removeClass("opacity0"); 188 // return; 189 // } 190 191 // Animate homepage elements in on timers 192 setTimeout(function () { 193 $(".header").addClass("animated fadeInUp"); 194 }, 50); 195 196 setTimeout(function () { 197 // Final animations 198 $(".opacity0").removeClass("opacity0"); 199 }, 4000); 200 } 201})(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.