// if scroll is greater than 100px, add class to body document.addEventListener('DOMContentLoaded', function () { document.addEventListener('scroll', checkIsScrolling); registerUserInteractionEvents(); checkIsScrolling(); addBodyLoaded(); scrollIfFragment(); registerNiceSelect(); registerProductFeatureToggles(); registerProductRotateButton(); registerTimeline(); registerETargets(); registerFeatureImagePreload(); registerControlsCableEntry(); registerCarousels(); registerVideoModal(); registerBurgerIcon(); registerCycleLocalCloud(); registerLanguageSelectChange(); registerFeatureCycle(); registerFaqItems(); registerLazySections(); }); function addBodyLoaded() { document.body.classList.add('js-ready'); document.documentElement.style.scrollPaddingTop = '80px'; } let languageSelect = null; function registerNiceSelect() { languageSelect = NiceSelect.bind(document.querySelector("select#language-select"), { searchable: true }); } function scrollIfFragment() { if (!window.location.hash) return; if (window.location.hash.startsWith('#faq-')) return; let elem = document.querySelector(window.location.hash); if (!elem) return; elem.scrollIntoView({ behavior: 'smooth' }); } function registerUserInteractionEvents() { // on mousemove, touchmove, scroll document.addEventListener('mousemove', userInteract, { passive: true, once: true }); document.addEventListener('touchmove', userInteract, { passive: true, once: true }); document.addEventListener('scroll', userInteract, { passive: true, once: true }); document.querySelectorAll('.nav-logo').forEach(logo => { logo.addEventListener('click', function () { window.scrollTo({ top: 0, behavior: 'smooth' }); }, { passive: true }); }); // load any video[data-src] elements that are in view const lazyVideos = document.querySelectorAll('video[data-src]'); if (lazyVideos) { lazyVideos.forEach(video => { if (video.getBoundingClientRect().top < window.innerHeight) { video.setAttribute('src', video.getAttribute('data-src')); video.removeAttribute('data-src'); } }); } } let interacted = false; function userInteract() { if (interacted) return; interacted = true; const lazyVideos = document.querySelectorAll('video[data-src]'); if (lazyVideos) { lazyVideos.forEach(video => { video.setAttribute('src', video.getAttribute('data-src')); video.removeAttribute('data-src'); }); } } let isPinned = false; function checkIsScrolling() { let header = document.querySelector('.vpe-nav'); if (window.scrollY > 80 && !isPinned) { header.classList.add('pinned'); isPinned = true; } else if (window.scrollY <= 80 && isPinned) { header.classList.remove('pinned'); isPinned = false; } } function registerProductFeatureToggles() { const buttons = document.querySelectorAll('#features .product-toggles .feature-toggle'); if (!buttons) return; const elem = document.querySelector('#features .product'); buttons.forEach(button => { button.addEventListener('click', function () { // if active, remove class if (button.classList.contains('active')) { button.classList.remove('active'); elem.setAttribute('data-feature', ''); return; } // remove active class from all buttons buttons.forEach(b => b.classList.remove('active')); // add active class to clicked button button.classList.add('active'); // set data-feature attribute to product elem.setAttribute('data-feature', button.getAttribute('data-feature')); }); }); } let eDepsloaded = false; let eAudio; let eDone = false; function registerETargets() { document.querySelectorAll('.etarget').forEach(elem => { elem.addEventListener('click', function () { elem.classList.add('active'); checkETargets(); }); }); setTimeout(() => { if (eDone || eDepsloaded) return; console.log(decodeURIComponent(escape(atob('Tm8gZWFzdGVyIGVnZ3MgdG8gZmluZCBoZXJlIPCfmYo=')))); }, 10000); } function checkETargets() { if (eDone) return; const targets = document.querySelectorAll('.etarget'); const total = targets.length; let active = [...targets].filter(target => target.classList.contains('active')).length; if (active > 3 && !eDepsloaded) { eDepsloaded = true; console.log(decodeURIComponent(escape(atob('SGV5ISBTdG9wIGNsaWNraW5nIHRob3NlIGJ1dHRvbnMg8J+kqg==')))); let script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/@tsparticles/confetti@3.0.3/tsparticles.confetti.bundle.min.js'; document.body.appendChild(script); // audio eAudio = document.createElement('audio'); eAudio.src = '/images/voice-pe/vpe-sound.mp3'; eAudio.autoplay = false; eAudio.loop = false; eAudio.volume = .5; document.body.appendChild(eAudio); } if (active === total) { eDone = true; console.log(decodeURIComponent(escape(atob('QWxyaWdodCwgSSBsaWVkLCB0aGVyZSB3YXMgYW4gZWFzdGVyIGVnZy4uLiDwn5iF')))); confetti({ particleCount: 100, spread: 100, scalar: 1.5, startVelocity: 80, ticks: 100, angle: 50, origin: { y: 1, x: 0 }, colors: ["#00AEF8"] }); setTimeout(() => { console.log(decodeURIComponent(escape(atob('QnV0IGNhbiB5b3UgZmluZCBhbm90aGVyIG9uZSBpbiBvdXIgVm9pY2UgUHJldmlldyBFZGl0aW9uPyDwn5iP')))); confetti({ particleCount: 100, spread: 100, scalar: 1.5, startVelocity: 80, ticks: 100, angle: 125, origin: { y: 1, x: 1 }, colors: ["#DB582E"] }); }, 500); setTimeout(() => { console.log(decodeURIComponent(escape(atob('R29vZCBsdWNrIQ==')))); eAudio.play(); }, 920); setTimeout(() => { console.log(decodeURIComponent(escape(atob('LURhcnJlbg==')))); confetti({ particleCount: 1000, spread: 360, scalar: 1.5, startVelocity: 150, ticks: 100, angle: 90, origin: { y: 1, x: .5 }, colors: ["#00AEF8", "#DB582E", "#16F3BE"] }); }, 1000); } } function registerProductRotateButton() { const button = document.querySelector('#features .product .button'); if (!button) return; const elem = document.querySelector('#features .product'); button.addEventListener('click', function () { // toggle data-side between left and right elem.setAttribute('data-side', elem.getAttribute('data-side') === 'left' ? 'right' : 'left'); // get first button on side const firstButton = elem.querySelector('.feature-toggle[data-side="' + elem.getAttribute('data-side') + '"]'); if (firstButton) { // remove active class from all buttons elem.querySelectorAll('.product-toggles .feature-toggle').forEach(b => b.classList.remove('active')); // add active class to first button firstButton.classList.add('active'); // set data-feature attribute to product elem.setAttribute('data-feature', firstButton.getAttribute('data-feature')); } }); } function registerTimeline() { const timeline = document.querySelector('#timeline'); if (!timeline) return; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { timeline.setAttribute('data-event', '2'); } }); }, { threshold: .25 }); observer.observe(timeline); } function registerFeatureImagePreload() { // add intersection observer to #product-features. Only execute once const features = document.querySelector('#features'); if (!features) return; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); preloadImage('/images/voice-pe/features/left-desktop.webp'); preloadImage('/images/voice-pe/features/left-mobile.webp'); } }); }, { threshold: .25 }); observer.observe(features); } function registerControlsCableEntry() { // add intersection observer to #product-features. Only execute once const controls = document.querySelector('#controls'); if (!controls) return; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); // remove loading="lazy" from all images controls.querySelectorAll('img').forEach(img => img.removeAttribute('loading')); controls.style.setProperty('--draw-cable', 1); setTimeout(() => { registerControlCycle(); }, 1000); } }); }, { threshold: .5 }); observer.observe(controls); } function preloadImage(url) { const link = document.createElement('link'); link.rel = 'preload'; link.as = 'image'; link.href = url; document.head.appendChild(link); } function registerControlCycle() { const controlsWrapper = document.querySelector('#controls'); if (!controlsWrapper) return; const innerControlsWrapper = controlsWrapper.querySelector('.controls'); if (!innerControlsWrapper) return const controls = innerControlsWrapper.querySelectorAll('.control'); if (!controls) return; let currentIndex = 1; controlsWrapper.setAttribute('data-index', currentIndex); controls[currentIndex - 1].classList.add('last'); // set data-index on controlsWrapper setInterval(() => { currentIndex = currentIndex === controls.length ? 1 : currentIndex + 1; innerControlsWrapper.setAttribute('data-index', currentIndex); controlsWrapper.setAttribute('data-index', 0); setTimeout(() => { controls.forEach(control => control.classList.remove('last')); controls[currentIndex - 1].classList.add('last'); controlsWrapper.setAttribute('data-index', currentIndex); }, 1000); }, 4000); } function registerCarousels() { // add intersection observer to #product-features. Only execute once const carousels = document.querySelectorAll('.carousel-images'); if (!carousels) return; carousels.forEach(carousel => { const slides = carousel.querySelectorAll('.slide'); if (!slides) return; const controls = carousel.querySelector('.controls'); if (controls) { controls.innerHTML = ''.repeat(slides.length); } // allow controls to be clicked if (controls) { const controlSpans = controls.querySelectorAll('span'); controlSpans.forEach((span, index) => { span.addEventListener('click', function () { resetCarousel(carousel, index); }); }); } const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); // set css variable for resetCarousel(carousel); } }); }, { threshold: .5 }); observer.observe(carousel); }); } let carouselInterval = null; function resetCarousel(carousel, slideIndex = 0) { clearInterval(carouselInterval); const slides = carousel.querySelectorAll('.slide'); if (!slides) return; if (slideIndex >= slides.length) { slideIndex = 0; } carousel.setAttribute('data-slide', slideIndex); carouselInterval = setInterval(() => { const currentIndex = parseInt(carousel.getAttribute('data-slide')); const nextIndex = currentIndex === slides.length - 1 ? 0 : currentIndex + 1; carousel.setAttribute('data-slide', nextIndex); }, 2500); } function registerVideoModal() { const video = document.querySelector('.timeline-content .video'); if (!video) return; const modal = document.querySelector('.video-modal'); if (!modal) return; const previewVideoElem = video.querySelector('video'); const modalVideoElem = modal.querySelector('video'); const modalClose = modal.querySelector('.close'); if (modalClose) { modalClose.addEventListener('click', function () { handleVideoModalClose(previewVideoElem, modal, modalVideoElem); }); } video.addEventListener('click', function () { handleVideoModalOpen(previewVideoElem, modal, modalVideoElem); }); modal.addEventListener('click', function (e) { if (e.target === modal) { handleVideoModalClose(previewVideoElem, modal, modalVideoElem); } }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') { handleVideoModalClose(previewVideoElem, modal, modalVideoElem); } }); } function handleVideoModalOpen(previewVideoElem, modal, modalVideoElem) { modal.classList.add('open'); document.body.classList.add('modal-open'); document.documentElement.style.overflow = "hidden"; previewVideoElem.pause(); modalVideoElem.controls = true; modalVideoElem.currentTime = 0; modalVideoElem.muted = false; modalVideoElem.play(); } function handleVideoModalClose(previewVideoElem, modal, modalVideoElem) { modal.classList.remove('open'); document.body.classList.remove('modal-open'); document.documentElement.style.overflow = ""; modalVideoElem.controls = false; modalVideoElem.pause(); previewVideoElem.play(); } function registerBurgerIcon() { const burger = document.querySelector('.burger'); if (!burger) return; const nav = document.querySelector('.vpe-nav'); if (!nav) return; burger.addEventListener('click', function () { nav.classList.toggle('mobile-open'); }); // if any of the burger links are clicked, close the nav const links = nav.querySelectorAll('a'); if (!links) return; links.forEach(link => { link.addEventListener('click', function () { nav.classList.remove('mobile-open'); }); }); } function registerCycleLocalCloud() { // add intersection observer to #product-features. Only execute once const sides = document.querySelector('#local-cloud .sides'); if (!sides) return; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); // set css variable for let lastSide = 'cloud'; let interval = null; interval = setInterval(() => { // toggle between data-side="local" and data-side="cloud" sides.setAttribute('data-side', ''); setTimeout(() => { lastSide = lastSide === 'local' ? 'cloud' : 'local'; sides.setAttribute('data-side', lastSide); }, 500); }, 5000); // if hover on left side, set to local sides.querySelector('.side.local').addEventListener('mouseenter', function () { clearInterval(interval); sides.setAttribute('data-side', 'local'); }); // if hover on right side, set to cloud sides.querySelector('.side.cloud').addEventListener('mouseenter', function () { clearInterval(interval); sides.setAttribute('data-side', 'cloud'); }); } }); }, { threshold: .5 }); observer.observe(sides); } function registerLanguageSelectChange() { const browserLocale = navigator.language || navigator.userLanguage; updateLanguageSupports(browserLocale); document.querySelector('#language-select').addEventListener('change', function (e) { updateLanguageSupports(e.target.value); }); } function updateLanguageSupports(locale = null) { let data = { "en-US": [3, 3], "es-ES": [3, 3], "pt-BR": [3, 3], "pt-PT": [2, 2], "de-DE": [3, 3], "de-CH": [0, 2], "it-IT": [2, 2], "ru-RU": [2, 2], "ja-JP": [0, 0], "tr-TR": [0, 1], "ko-KR": [0, 1], "fr-FR": [0, 3], "ca-ES": [0, 3], "pl-PL": [0, 3], "nl-BE": [0, 3], "nl-NL": [0, 3], "id-ID": [0, 1], "zh-HK": [0, 2], "zh-CN": [0, 1], "ms-MY": [0, 1], "sv-SE": [0, 2], "uk-UA": [0, 2], "th-TH": [0, 1], "vi-VN": [0, 1], "fi-FI": [0, 3], "no-NO": [0, 0], "gl-ES": [0, 2], "ar-JO": [0, 2], "ur-IN": [0, 0], "el-GR": [0, 1], "ro-RO": [0, 3], "da-DK": [0, 2], "ta-IN": [0, 0], "hr-HR": [0, 3], "mk-MK": [0, 0], "sk-SK": [0, 1], "he-IL": [0, 2], "sr-RS": [0, 1], "hu-HU": [0, 3], "bg-BG": [0, 2], "cs-CZ": [0, 1], "bs-BA": [0, 0], "sl-SI": [0, 2], "az-AZ": [0, 0], "et-EE": [0, 1], "lv-LV": [0, 1], "af-ZA": [0, 0], "cy-GB": [0, 0], "fa-IR": [0, 1], "lt-LT": [0, 1], "jv-ID": [0, 0], "sw-KE": [0, 0], "sw-TZ": [0, 0], "is-IS": [0, 1], "mt-MT": [0, 0], "ps-AF": [0, 0], "mr-IN": [0, 0], "bn-IN": [0, 0], "lb-LU": [0, 0], "hi-IN": [0, 0], "gu-IN": [0, 0], "km-KH": [0, 0], "ne-NP": [0, 0], "lo-LA": [0, 0], "te-IN": [0, 1], "kn-IN": [0, 0], "ml-IN": [0, 1], "kk-KZ": [0, 0], "so-SO": [0, 0], "uz-UZ": [0, 0], "ka-GE": [0, 1], "my-MM": [0, 0], "mn-MN": [0, 0], "hy-AM": [0, 0], "am-ET": [0, 0], "nb-NO": [0, 3], "eu-ES": [0, 1], "fil-PH": [0, 0], "ga-IE": [0, 0], "si-LK": [0, 0], "sq-AL": [0, 0], "su-ID": [0, 0], "wuu-CN": [0, 0], "yue-CN": [0, 0], "zu-ZA": [0, 0] }; let elems = document.querySelectorAll('.supported-cards .supported-card'); if (!elems) return; let supports = data[locale]; let foundLocale = locale; if (!supports) { Object.keys(data).forEach(key => { if (key.split('-')[0] === locale.split('-')[0]) { supports = data[key]; foundLocale = key; } }); } if (!supports) return; document.querySelector('#language-select').value = foundLocale; languageSelect.update(); elems.forEach(elem => elem.setAttribute('data-state', '-1')); elems.forEach((elem, index) => { // set data-state to the value of the value elem.setAttribute('data-state', supports[index]); }); } function registerFeatureCycle() { const featuresElem = document.querySelector('#features'); const rotateBtn = document.querySelector('#features .button'); const features = document.querySelectorAll('#features .feature-toggle'); let interval = null; rotateBtn.addEventListener('click', function () { if (interval) { clearInterval(interval); interval = null; return; } }); features.forEach((feature, index) => { feature.addEventListener('click', function () { if (interval) { clearInterval(interval); interval = null; return; } }); }); let availableStates = [ ["microphones", "right"], ["case", "right"], ["mute", "right"], ["speaker", "right"], ["controls", "left"], ["led-ring", "left"], ["audio-jack", "left"] ] let currentIndex = 0; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); // set css variable for interval = setInterval(() => { currentIndex = currentIndex === availableStates.length - 1 ? 0 : currentIndex + 1; let state = availableStates[currentIndex]; document.querySelector('#features .product').setAttribute('data-feature', state[0]); document.querySelector('#features .product').setAttribute('data-side', state[1]); document.querySelectorAll('#features .product-toggles .feature-toggle').forEach(feature => { feature.classList.remove('active'); }); document.querySelector('#features .product-toggles .feature-toggle[data-feature="' + state[0] + '"]').classList.add('active'); }, 5000); } }); }, { threshold: .5 }); observer.observe(featuresElem); } function registerFaqItems() { const faqItems = document.querySelectorAll('.faq-item'); if (!faqItems) return; faqItems.forEach(faqItem => { let header = faqItem.querySelector('.faq-item-heading'); header.addEventListener('click', function () { faqItem.classList.toggle('active'); }); }); // if url contains id of faq item, open it faqItems.forEach(faqItem => { if (!faqItem.id) return; if (window.location.hash === '#' + faqItem.id) { faqItem.scrollIntoView({ behavior: 'smooth' }); setTimeout(() => { faqItem.classList.add('active'); }, 1000); } document.querySelectorAll('a[href="#' + faqItem.id + '"]').forEach(link => { link.addEventListener('click', function () { faqItem.scrollIntoView({ behavior: 'smooth' }); setTimeout(() => { faqItem.classList.add('active'); }, 1000); }); }); }); } function showBuyDialog() { buyDialog.style.display = "flex"; document.documentElement.style.overflow = "hidden"; } function closeDialog() { buyDialog.style.display = "none"; document.documentElement.style.overflow = ""; } function randomInRange(min, max) { return Math.random() * (max - min) + min; } function registerLazySections() { // for each section, register an intersection observer at 0.0. If it is intersecting, disconnect. Then, make any data-src images load const sections = document.querySelectorAll('.vpe-main section'); if (!sections) return; sections.forEach(section => { const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { observer.disconnect(); loadLazyImages(section); } }); }, { threshold: 0, rootMargin: '80px' }); observer.observe(section); }); } function loadLazyImages(section) { const lazyImages = section.querySelectorAll('img[data-src]'); if (!lazyImages) return; lazyImages.forEach(img => { img.setAttribute('src', img.getAttribute('data-src')); img.removeAttribute('data-src'); }); let lazyBackgrounds = section.querySelectorAll('[data-bg-image-lazy]'); if (!lazyBackgrounds) return; lazyBackgrounds.forEach(lazyBackground => { // remove the attribute lazyBackground.removeAttribute('data-bg-image-lazy'); }); }