1(function($){ 2 /* Browser Detection 3 ---------------------------------------------------------------------- */ 4 // Detect mobile device 5 var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Nokia|Opera Mini/i.test(navigator.userAgent) ? true : false; 6 7 // Add class "is-mobile" to </body> 8 if(isMobile) { 9 $("body").addClass("is-mobile"); 10 } 11 12 /* Responsive Sizing Variables 13 ---------------------------------------------------------------------- */ 14 var win = $(window); 15 var headerHeight = $(".header-wrapper").outerHeight(); 16 //var swiperHeight = win.height() - headerHeight; 17 var scroll_bar_width = getScrollbarWidth(); 18 var scroll_bar_half_width = scroll_bar_width/2; 19 20 win.bind("load resize blur focus", function() { 21 headerHeight = $(".header-wrapper").outerHeight(); 22 //swiperHeight = win.height() - headerHeight; 23 scroll_bar_width = getScrollbarWidth(); 24 scroll_bar_half_width = scroll_bar_width/2; 25 26 // This calculated CSS variable is needed to properly calculate the .alignfull class, taking into account the browser's scrollbar width 27 $("html").attr('body','--scroll-bar-half-width:' + scroll_bar_half_width + 'px'); 28 $("body").css('--scroll-bar-half-width',scroll_bar_half_width + 'px'); 29 30 // Offset the hero content by the height of the header in order to center it within the area unobscured by the fixed header 31 $('.section-hero-content-container').css('padding-top', headerHeight); 32 }); 33 34 function getScrollbarWidth() { 35 var div = $('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>'); 36 // Append our div, do our calculation and then remove it 37 $('body').append(div); 38 var w1 = $('div', div).innerWidth(); 39 div.css('overflow-y', 'scroll'); 40 var w2 = $('div', div).innerWidth(); 41 $(div).remove(); 42 return (w1 - w2); 43 } 44 45 /* Animations trigger on scroll 46 ---------------------------------------------------------------------- */ 47 $(function(){ 48 new WOW().init(); 49 }); 50 51 /* Parallax Initialization 52 ---------------------------------------------------------------------- */ 53 $(function(){ 54 var parallaxEL = document.getElementsByClassName('parallax-bg'); 55 var parallax = new simpleParallax(parallaxEL, { 56 scale: 1.5, 57 orientation: 'down', 58 }); 59 }); 60 61 /* Initialize :: Magnific 62 ---------------------------------------------------------------------- */ 63 $(function(){ 64 $('.popup-youtube, .popup-video, .popup-vimeo, .popup-gmaps').magnificPopup({ 65 type: 'iframe', 66 mainClass: 'mfp-fade', 67 removalDelay: 160, 68 preloader: false, 69 fixedContentPos: false 70 }); 71 72 $('.popup-media').magnificPopup({ 73 type: 'image' 74 }); 75 }); 76 77 /* Functionality :: Sticky Header Animation 78 ---------------------------------------------------------------------- */ 79 $(function(){ 80 81 // Add a class of 'is-stuck' to the sticky header when it is pinned for styling purposes 82 var observer = new IntersectionObserver(function(entries) { 83 if(entries[0].intersectionRatio === 0){ 84 document.querySelector("#header-wrapper").classList.add("is-stuck"); 85 86 var headerHeightScrolled = $(".header-wrapper").outerHeight(); 87 88 // Add an offset for sticky elements based on the height of the scrolled header 89 $(".sticky-top:not(.header-wrapper)").css("top", headerHeightScrolled + 15); 90 91 // Add an offset for scroll target elements based on the height of the scrolled header, plus an additional 15px of padding 92 $(':target').css('scroll-margin-top', headerHeightScrolled + 15); 93 94 } else if(entries[0].intersectionRatio === 1){ 95 document.querySelector("#header-wrapper").classList.remove("is-stuck"); 96 } 97 }, { threshold: [0,1] }); 98 99 observer.observe(document.querySelector("#header-wrapper-spacer")); 100 101 }); 102 103 /* Initialize :: Swipers 104 ---------------------------------------------------------------------- */ 105 $(function(){ 106 107 // Check for the existence of more than one slide before initializing. 108 if ($(".swiper-home").length && ($(".swiper-home .swiper-wrapper .swiper-slide").length > 1) ) { 109 var swiperHome = new Swiper(".swiper-home .swiper-container", { 110 grabCursor: true, 111 effect: 'fade', 112 fadeEffect: { 113 crossFade: true 114 }, 115 speed: 1000, 116 spaceBetween: 0, 117 centeredSlides: true, 118 slidesPerView: 1, 119 slideToClickedSlide: true, 120 watchOverflow: true, 121 loop: true, 122 autoplay: { 123 delay: 7000, 124 }, 125 pagination: { 126 el: ".swiper-pagination", 127 }, 128 on: { 129 init: function () { 130 131 var $this = this; 132 var $slideActive = $($this.slides[$this.activeIndex]); 133 134 // Play video on load 135 if(!isMobile) { 136 $slideActive.find("video").each(function() { 137 $(this).get(0).play(); 138 }); 139 } 140 }, 141 142 transitionStart: function () { 143 144 var $this = this; 145 var $slideActive = $($this.slides[$this.activeIndex]); 146 147 // Play video 148 //if(!isMobile) { 149 $slideActive.find("video").each(function() { 150 $(this).get(0).play(); 151 }); 152 //} 153 154 }, 155 156 transitionEnd: function () { 157 var $this = this; 158 var $slideActive = $($this.slides[$this.activeIndex]); 159 160 // Pause video 161 $slideActive.prevAll().find("video").each(function() { 162 $(this).get(0).pause(); 163 }); 164 $slideActive.nextAll().find("video").each(function() { 165 $(this).get(0).pause(); 166 }); 167 } 168 } 169 }); 170 } else { 171 $(".swiper-home .swiper-button-next").hide(); 172 $(".swiper-home .swiper-button-prev").hide(); 173 } 174 175 if ($(".swiper-testimonials").length) { 176 177 $( ".swiper-testimonials .testimonial-block" ).wrap( "<div class='swiper-slide py-4 px-5'></div>" ); 178 179 var swiperTestimonials = new Swiper(".swiper-testimonials .swiper-container", { 180 effect: "slide", 181 grabCursor: true, 182 spaceBetween: 0, 183 centeredSlides: true, 184 slidesPerView: 1, 185 slideToClickedSlide: true, 186 187 loop: true, 188 autoplay: { 189 delay: 7000, 190 }, 191 navigation: { 192 nextEl: ".swiper-testimonials .swiper-button-next", 193 prevEl: ".swiper-testimonials .swiper-button-prev", 194 } 195 }); 196 } 197 198 // Swiper :: Posts 199 if ($(".swiper-posts").length) { 200 var swiperPosts = new Swiper(".swiper-posts .swiper-container", { 201 grabCursor: true, 202 spaceBetween: 0, 203 slidesPerView: 1, 204 centeredSlides: false, 205 slideToClickedSlide: true, 206 loop: false, 207 watchOverflow: true, 208 breakpoints: { 209 575: { 210 slidesPerView: 2, 211 centeredSlides: false, 212 }, 213 992: { 214 slidesPerView: 3, 215 centeredSlides: false, 216 } 217 }, 218 navigation: { 219 nextEl: ".swiper-posts .swiper-button-next", 220 prevEl: ".swiper-posts .swiper-button-prev", 221 } 222 }); 223 } 224 225 }); 226 227/* Countdown Timers 228---------------------------------------------------------------------- */ 229 230class Countdown { 231 constructor(el) { 232 this.el = el; 233 234 // Standard attribute on <time> 235 const dt = el.getAttribute("datetime"); 236 this.targetDate = new Date(dt); 237 238 // Guard: if invalid date, bail (optional but helpful) 239 if (Number.isNaN(this.targetDate.getTime())) { 240 // eslint-disable-next-line no-console
241 console.warn("Countdown: invalid datetime attribute:", dt, el); 242 return; 243 } 244 245 this.createCountDownParts(); 246 this.countdownFunction(); 247 248 this.countdownLoopId = setInterval( 249 this.countdownFunction.bind(this), 250 1000 251 ); 252 } 253 254 createCountDownParts() { 255 ["days", "hours", "minutes", "seconds"].forEach((part) => { 256 const partEl = document.createElement("div"); 257 partEl.classList.add("countdown-part", part); 258 259 const partInnerEl = document.createElement("div"); 260 partInnerEl.classList.add("countdown-part-inner"); 261 262 const labelEl = document.createElement("span"); 263 labelEl.classList.add("countdown-label"); 264 labelEl.innerText = part; 265 266 const numberEl = document.createElement("div"); 267 numberEl.classList.add("countdown-number", "h2", "mb-0"); 268 numberEl.innerText = "0"; 269 270 partInnerEl.append(numberEl, labelEl); 271 partEl.append(partInnerEl); 272 273 this.el.append(partEl); 274 275 // Store the INNER wrapper so CSS vars work and we can update number text easily 276 this[part] = partInnerEl; 277 }); 278 } 279 280 countdownFunction() { 281 const currentDate = new Date(); 282 283 if (currentDate >= this.targetDate) { 284 clearInterval(this.countdownLoopId); 285 // Optionally force zeros at the end: 286 ["days", "hours", "minutes", "seconds"].forEach((part) => { 287 this[part].style.setProperty("--value", 0); 288 this[part].children[0].innerText = "0"; 289 }); 290 return; 291 } 292 293 const remaining = this.getRemaining(this.targetDate, currentDate); 294 295 Object.entries(remaining).forEach(([part, value]) => { 296 this[part].style.setProperty("--value", value); 297 this[part].children[0].innerText = String(value); 298 }); 299 } 300 301 getRemaining(target, now) { 302 let seconds = Math.floor((target - now) / 1000); 303 let minutes = Math.floor(seconds / 60); 304 let hours = Math.floor(minutes / 60); 305 let days = Math.floor(hours / 24); 306 307 hours = hours - days * 24; 308 minutes = minutes - (days * 24 * 60) - (hours * 60); 309 seconds = seconds - (days * 24 * 60 * 60) - (hours * 60 * 60) - (minutes * 60); 310 311 return { days, hours, minutes, seconds }; 312 } 313} 314 315// Initialize once DOM is ready (covers cases where script is in <head>) 316document.addEventListener("DOMContentLoaded", () => { 317 const countdownEls = document.querySelectorAll(".countdown"); 318 countdownEls.forEach((countdownEl) => new Countdown(countdownEl)); 319}); 320 321 322 323 /* Functionality :: Layering utility class 324 ---------------------------------------------------------------------- */ 325 function layerUp(){ 326 var layerHeight; 327 328 $('.layer-up').each(function(i, obj) { 329 330 layerHeight = $(this).outerHeight() / 2; 331 332 $(this).prev().css("padding-bottom", layerHeight); 333 $(this).children(".layer-up-content").css("margin-top", -layerHeight); 334 335 }); 336 } 337 $(window).resize(function() { 338 layerUp(); 339 }); 340 341 $(document).ready(function() { 342 layerUp(); 343 }); 344 345 /* Desktop Search Functionality 346 ---------------------------------------------------------------------- */ 347 $(document).ready(function() { 348 "use strict"; 349 350 // Remove Search if user Resets Form or hits Escape 351 $('.navbar-top-collapse form[role="search"] button[type="reset"]').on('click keyup', function(event) { 352 if (event.which == 27 && $('.navbar-top-collapse form[role="search"]').hasClass('active') || $(event.currentTarget).attr('type') == 'reset') { 353 closeSearch(); 354 } 355 }); 356 357 function closeSearch() { 358 var $form = $('.navbar-top-collapse form[role="search"].active') 359 $form.find('input').val(''); 360 $form.removeClass('active'); 361 } 362 363 // Show Search if form is not active // event.preventDefault() is important, this prevents the form from submitting 364 $(document).on('click', '.navbar-top-collapse form[role="search"]:not(.active) button[type="submit"]', function(event) { 365 event.preventDefault(); 366 var $form = $(this).closest('form'), 367 $input = $form.find('input'); 368 $form.addClass('active'); 369 $input.focus(); 370 }); 371 372 $('a[href="#header-search-desktop"]').on('click', function(event) { 373 event.preventDefault(); 374 $('#header-search-desktop').addClass('open'); 375 $('#header-search-desktop > form > input[type="search"]').focus(); 376 }); 377 378 $('#header-search-desktop, #header-search-desktop button.close').on('click keyup', function(event) { 379 if (event.target == this || event.target.classList.contains('fa-times') || event.keyCode == 27) { 380 $(this).removeClass('open'); 381 } 382 }); 383 }); 384 385 /* Bootstrap Fix :: Always append all modals to the end of the HTML body to take care of any z-indexing issues 386 ---------------------------------------------------------------------- */ 387 $(document).ready(function($){ 388 $('.modal-dialog').parent().on('show.bs.modal', function(e){ $(e.relatedTarget.attributes['data-bs-target'].value).appendTo('body'); }); 389 }); 390 391 /* Polyfill :: Object-fit CSS IE 11 Fallback 392 ---------------------------------------------------------------------- */ 393 // Detect objectFit support 394 if('objectFit' in document.documentElement.style === false) { 395 396 // assign HTMLCollection with parents of images with objectFit to variable 397 var container = document.getElementsByClassName('tab-pane-image'); 398 399 // Loop through HTMLCollection 400 for(var i = 0; i < container.length; i++) { 401 // Asign image source to variable 402 var imageSource = container[i].querySelector('img').src; 403 404 // Hide image 405 container[i].querySelector('img').style.display = 'none'; 406 407 // Add background-size: cover 408 container[i].style.backgroundSize = 'cover'; 409 410 // Add background-image: and put image source here
411 container[i].style.backgroundImage = 'url(' + imageSource + ')'; 412 413 // Add background-position: center center 414 container[i].style.backgroundPosition = 'center center'; 415 } 416 } 417 418 /* Initialize :: Mobile Navigation 419 ---------------------------------------------------------------------- */ 420 $(function(){ 421 "use strict"; 422 jQuery("#menu-toggle").click(function(e) { 423 e.preventDefault(); 424 jQuery("#site-wrapper").toggleClass("toggled"); 425 }); 426 }); 427 428})(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.