1// vanilla js 2'use strict'; 3 4let THEME_PATH = wp_helper.home_path + '/'; 5 6document.addEventListener('DOMContentLoaded', () => { 7 loadFonts(); 8 correctVh(); 9 lazyLoad(); 10 mobileMenu(); 11 initTestimonialSlider(); 12 initImageSlider(); 13 initPostSlider(); 14 initCustomSelect(); 15 initAnimation(); 16 initVisual(); 17 initFlipNum(); 18}); 19 20window.addEventListener('resize', () => { 21 correctVh(); 22}); 23 24window.addEventListener('load', () => { 25 setTimeout(initReadMore, 300); 26}); 27 28// load fonts 29function loadFonts() { 30 WebFont.load({ 31 google: { 32 families: ['Montserrat:400,500,600,700'], 33 }, 34 custom: { 35 families: ['Font Awesome 6 Free', 'Font Awesome 6 Brands'], 36 urls: [THEME_PATH + 'css/fonts.css'], 37 } 38 }); 39} 40 41// lazyLoad Images 42function lazyLoad() { 43 const images = document.querySelectorAll('img.lazyload'); 44 45 if (images.length) { 46 images.forEach(function (img) { 47 img.onload = function() { 48 img.classList.add('lazyloaded'); 49 50 if (img.classList.contains('svg-html')) { 51 replaseInlineSvg(img); 52 } 53 }; 54 }); 55 56 window.addEventListener('load', (e) => { 57 images.forEach(img => { 58 if (img.complete && img.naturalHeight !== 0) { 59 img.classList.add('lazyloaded'); 60 61 if (img.classList.contains('svg-html')) { 62 replaseInlineSvg(img); 63 } 64 } 65 }); 66 }); 67 } 68} 69 70// replaseInlineSvg 71function replaseInlineSvg(el) { 72 const imgID = el.getAttribute('id'); 73 const imgClass = el.getAttribute('class'); 74 const imgURL = el.getAttribute('src'); 75 76 fetch(imgURL) 77 .then(data => data.text()) 78 .then(response => { 79 const parser = new DOMParser(); 80 const xmlDoc = parser.parseFromString(response, 'text/html'); 81 let svg = xmlDoc.querySelector('svg'); 82 83 if (typeof imgID !== 'undefined') { 84 svg.setAttribute('id', imgID); 85 } 86 87 if (typeof imgClass !== 'undefined') { 88 svg.setAttribute('class', imgClass + ' replaced-svg'); 89 } 90 91 svg.removeAttribute('xmlns:a'); 92 93 if (el.parentNode) { 94 el.parentNode.replaceChild(svg, el); 95 } 96 }); 97} 98 99// correctVh 100function correctVh() { 101 let vh = window.innerHeight * 0.01; 102 document.documentElement.style.setProperty('--vh', vh+'px'); 103} 104 105// mobile menu 106function mobileMenu() { 107 const openBtn = document.querySelector('.navbar-toggler'); 108 109 if (openBtn) { 110 openBtn.addEventListener('click', function(event) { 111 event.preventDefault(); 112 if ( document.body.classList.contains('menu-opened') ) { 113 document.body.classList.remove('menu-opened'); 114 } else { 115 document.body.classList.add('menu-opened'); 116 } 117 }); 118 } 119} 120 121function initTestimonialSlider() {
122 document.querySelectorAll('.testimonial-slider').forEach(sliderEl => { 123 const swiper = new Swiper(sliderEl, { 124 loop: true, 125 slidesPerView: 1, 126 navigation: { 127 nextEl: '.swiper-button-next', 128 prevEl: '.swiper-button-prev', 129 }, 130 pagination: { 131 el: '.swiper-pagination', 132 type: 'bullets', 133 }, 134 breakpoints: { 135 992: { 136 slidesPerView: 2, 137 }, 138 }, 139 }); 140 }); 141} 142 143function initImageSlider() { 144 document.querySelectorAll('.image-slider').forEach(sliderEl => { 145 const swiper = new Swiper(sliderEl, { 146 loop: true, 147 autoplay: { 148 delay: 4000, 149 }, 150 slidesPerView: 1, 151 navigation: { 152 nextEl: '.swiper-button-next', 153 prevEl: '.swiper-button-prev', 154 } 155 }); 156 }); 157} 158 159function initPostSlider() { 160 document.querySelectorAll('.post-slider').forEach(sliderEl => { 161 const swiper = new Swiper(sliderEl, { 162 loop: false, 163 slidesPerView: 1, 164 spaceBetween: 30, 165 slideVisibleClass: 'swiper-slide-visible', 166 navigation: { 167 nextEl: '.swiper-button-next', 168 prevEl: '.swiper-button-prev', 169 }, 170 breakpoints: { 171 992: { 172 slidesPerView: 3, 173 }, 174 768: { 175 slidesPerView: 2, 176 }, 177 }, 178 }); 179 }); 180} 181 182function initCustomSelect() { 183 const SELECTED_CLASS = 'filled'; 184 185 document.querySelectorAll('select').forEach((selectEl) => { 186 const selIx = selectEl.selectedIndex; 187 let optsPlaceholder = null; 188 189 if (selIx === 0) { 190 const selOpt = selectEl.querySelectorAll('option')[selIx]; 191 optsPlaceholder = selOpt.text; 192 } 193 194 checkSelectState(selectEl); 195 selectEl.addEventListener('change', (e) => { 196 checkSelectState(selectEl); 197 window.sr.destroy('.animation-fade'); 198 }); 199 200 NiceSelect.bind(selectEl, { 201 // options 202 placeholder: optsPlaceholder, 203 }); 204 }); 205 206 function checkSelectState(selectEl) { 207 const val = selectEl.value; 208 // if (val === '-1') { 209 if (val === '') { 210 if (selectEl.classList.contains(SELECTED_CLASS)) { 211 selectEl.classList.remove(SELECTED_CLASS); 212 } 213 } else { 214 if (!selectEl.classList.contains(SELECTED_CLASS)) { 215 selectEl.classList.add(SELECTED_CLASS); 216 } 217 } 218 } 219} 220 221function initReadMore() { 222 document.querySelectorAll('.trunc-holder').forEach(truncEl => { 223 const nextEl = truncEl.nextElementSibling; 224 const moreEl = nextEl.classList.contains('trunc-more') ? nextEl : null; 225 const dot = new Dotdotdot(truncEl, { 226 ellipsis: '...', 227 }); 228 229 if (moreEl) { 230 moreEl.addEventListener('click', (e) => { 231 e.preventDefault(); 232 dot.API.restore(); 233 moreEl.classList.add('hidden'); 234 }); 235 } 236 }); 237} 238 239function initAnimation(selector = '') { 240 window.sr = ScrollReveal(); 241 let revealSelector = '.animation-fade'; 242 if (selector != '' && document.querySelector(selector)) { 243 revealSelector = selector+' '+revealSelector; 244 } 245 sr.reveal(revealSelector, { 246 scale: 1, 247 reset: false, 248 mobile: true, 249 duration: 2500, 250 distance: '0px', 251 origin: 'bottom' 252 }); 253} 254 255function initVisual() { 256 document.querySelectorAll('.visual h1, .visual .h1').forEach(headEl => { 257 const headContent = headEl.innerHTML; 258 headEl.innerHTML = ''; 259 260 const textEl = headEl.closest('.visual').querySelector('p'); 261 let textContent; 262 263 if (textEl) { 264 textContent = textEl.innerHTML; 265 textEl.innerHTML = ''; 266 } 267 268 const typed = new Typed(headEl, { 269 stringsElement: null, 270 strings: [headContent], 271 typeSpeed: 50, 272 backSpeed: 0, 273 backDelay: 500, 274 startDelay: 1000, 275 loop: false, 276 showCursor: false, 277 onComplete: function(self) { 278 headEl.classList.add('anim-finished'); 279 280 if (textEl) { 281 new Typed(textEl, { 282 stringsElement: null, 283 strings: [textContent], 284 typeSpeed: 50, 285 backSpeed: 0, 286 backDelay: 500, 287 startDelay: 1000, 288 loop: false, 289 showCursor: false, 290 onComplete: function(self) { 291 textEl.classList.add('anim-finished'); 292 }, 293 onBegin: function(self) { 294 textEl.classList.add('anim-started'); 295 }, 296 }); 297 } 298 }, 299 }); 300 }) 301} 302 303function initFlipNum() { 304 document.querySelectorAll('.flip-num').forEach(counter => { 305 counter.innerText = '0' //set default counter value 306 counter.dataset.count = 0; 307 308 const updateCounter = () => { 309 const target = +counter.getAttribute('data-target').replace(',', ''); //define increase couter to it's data-target 310 const count = +counter.dataset.count; //define increase couter on innerText 311 const increment = target / 200; // define increment as counter increase value / speed 312 313 counter.classList.add('num-started'); 314 if (count < target) {
315 const newCount = Math.ceil(count + increment); 316 counter.dataset.count = newCount; 317 counter.innerText = numberWithCommas(newCount); 318 setTimeout(updateCounter, 1); 319 } else { 320 counter.innerText = numberWithCommas(target); //if default value is bigger that date-target, show data-target 321 } 322 } 323 324 check(); 325 window.addEventListener('scroll', check); 326 window.addEventListener('resize', check); 327 328 function check() { 329 if (isElementInViewport(counter) && !counter.classList.contains('num-started')) { 330 updateCounter(); 331 } 332 } 333 }); 334 335 function numberWithCommas(x) { 336 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 337 } 338 339 340} 341 342function isElementInViewport(el, horK, vertK) { 343 horK = horK || 0.75; 344 vertK = vertK || 0.5; 345 var rect = el.getBoundingClientRect(); 346 var windowHeight = (window.innerHeight || document.documentElement.clientHeight); 347 var windowWidth = (window.innerWidth || document.documentElement.clientWidth); 348 var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0) && ((rect.top + rect.height * vertK) <= windowHeight); 349 var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0) && ((rect.left + rect.width * horK) <= windowWidth); 350 351 return (vertInView && horInView); 352} 353 354// jQuery 355(function($){ 356 357 $(document).ready(function() { 358 $('.wpcf7-submit').addClass('btn btn-sm btn-secondary'); 359 initSidebarStick(); 360 361 // Hubspot forms in modals 362 $('.modal.has-hubspot').each( function() { 363 364 var $this = $(this), 365 modal_id = $this.attr('id'), 366 hubspot_id = $this.find('[data-hubspot-form-id]').attr('data-hubspot-form-id'); 367 368 var modal_el = document.getElementById(modal_id); 369 modal_el.addEventListener('show.bs.modal', function (event) { 370 371 hbspt.forms.create({ 372 region: "na1", 373 portalId: "22238080", 374 target: '#'+modal_id+' .hubspot-form', 375 formId: "a1967355-a05c-4359-a39b-1c59f28d5b39" 376 }); 377 }); 378 379 }); 380 381 }); // ready 382 383 $(window).on('resize', function() { 384 initSidebarStick(); 385 }); // resize 386 387 $(window).on('load', function() { 388 }); // load 389 390 /* ------------------------------------------------- */ 391 /* Refresh Jobs */ 392 393 $(document).on('click', '.refresh-jobs', function(e) { 394 395 e.preventDefault(); 396 397 var $button = $(this); 398 399 /* Loading */ 400 function do_loading() { 401 402 $button.addClass('loading'); 403 404 } 405 406 /* Loaded */ 407 function do_loaded() { 408 409 $button.removeClass('loading'); 410 setTimeout( function() { 411 location.reload(); 412 }, 1000); 413 414 } 415 416 /* Get Lisings */ 417 $.ajax({ 418 url: wp_helper.ajax_url, 419 type: 'POST', 420 data: { 421 action: 'refresh_jobs' 422 }, 423 dataType: "json", 424 beforeSend:function(xhr) { 425 426 do_loading(); 427 428 }, 429 success:function(data) { 430 431 do_loaded(); 432 433 } 434 }); 435 436 }); 437 438 /* ------------------------------------------------- */ 439 /* Sidebar Stick */ 440 441 function initSidebarStick() { 442 443 $('.sidebar.stick-it .sidebar-inner').each( function() { 444 445 var $this = $(this), 446 window_width = $(window).width(), 447 $header_bar = $('#header'), 448 sidebarHeight = $this.height(); 449 450 if ( window_width > 991 ) { 451 452 var offset_top = $header_bar.outerHeight() + 30; 453 454 $this.stick_in_parent({ 455 offset_top: offset_top, 456 parent: '.sidebar' 457 }); 458 459 } 460 461 }); 462 463 } 464 465 // jQuery functions 466})(this.jQuery); 467 468/* ------------------------------------------------- */ 469/* iFrame Videos */ 470 471 document.addEventListener('DOMContentLoaded', function () { 472 473 // Sizing 474 const wrapper = document.querySelector('.iframe-video-wrapper'); 475 if (wrapper) { 476 const iframe = wrapper.querySelector('iframe'); 477 const videoAspectRatio = 16 / 9; 478 function resizeIframe() { 479 const wrapperWidth = wrapper.offsetWidth; 480 const wrapperHeight = wrapper.offsetHeight;
481 const wrapperAspectRatio = wrapperWidth / wrapperHeight; 482 let newWidth, newHeight; 483 if (wrapperAspectRatio < videoAspectRatio) { 484 // Wrapper is wider than video: scale by height 485 newHeight = wrapperHeight; 486 newWidth = newHeight * videoAspectRatio; 487 } else { 488 // Wrapper is taller than video: scale by width 489 newWidth = wrapperWidth; 490 newHeight = newWidth / videoAspectRatio; 491 } 492 if (iframe) { 493 iframe.style.width = `${newWidth}px`; 494 iframe.style.height = `${newHeight}px`; 495 iframe.style.top = `${(wrapperHeight - newHeight) / 2}px`; 496 iframe.style.left = `${(wrapperWidth - newWidth) / 2}px`; 497 } 498 } 499 resizeIframe(); 500 window.addEventListener('resize', resizeIframe); 501 } 502 503 // Play/Pause 504 const wrappers = document.querySelectorAll('.iframe-video-wrapper'); 505 wrappers.forEach(wrapper => { 506 const iframe = wrapper.querySelector('iframe'); 507 const button = wrapper.querySelector('.play-button'); 508 509 if (!iframe) return; 510 511 const player = new Vimeo.Player(iframe); 512 let isPlaying = false; 513 514 // Wait for player to be fully ready 515 player.ready().then(() => { 516 console.log('â Vimeo player ready'); 517 wrapper.classList.add('ready'); 518 519 // Initial muted state (safer) 520 player.setMuted(true).catch(() => {}); 521 }).catch(err => { 522 console.error('Player init failed:', err); 523 }); 524 525 button.addEventListener('click', () => { 526 if (!isPlaying) { 527 player.ready().then(() => { 528 // CRITICAL: Unmute + set volume INSIDE the user click gesture 529 return Promise.all([ 530 player.setMuted(false), 531 player.setVolume(1.0) 532 ]); 533 }).then(() => { 534 return player.play(); 535 }).then(() => { 536 isPlaying = true; 537 wrapper.classList.add('playing'); 538 wrapper.classList.remove('paused'); 539 console.log('â¶ï¸ Playing with sound'); 540 }).catch(err => { 541 console.error('Play failed:', err); 542 }); 543 } else { 544 player.pause().then(() => { 545 isPlaying = false; 546 wrapper.classList.add('paused'); 547 wrapper.classList.remove('playing'); 548 }).catch(err => { 549 console.error('Pause failed:', err); 550 }); 551 } 552 }); 553 }); 554 555 });
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.