/* ===================================================================== PT SERLINDO PRIMA ENERGI — CORE FRONTEND JS Handles: mobile nav, WA widget, counters, swiper carousels, accordions, tabs, modals, video gallery playlist. No framework dependency — vanilla JS only. ===================================================================== */ document.addEventListener('DOMContentLoaded', function () { /* ---------- Mobile navbar toggle ---------- */ const navToggle = document.getElementById('navbarToggle'); const navMenu = document.getElementById('navbarMenu'); if (navToggle && navMenu) { navToggle.addEventListener('click', () => navMenu.classList.toggle('open')); // Tap-to-expand dropdowns on mobile navMenu.querySelectorAll('li > a').forEach(link => { link.addEventListener('click', function (e) { const parentLi = this.parentElement; const submenu = parentLi.querySelector(':scope > .dropdown-menu'); if (submenu && window.innerWidth <= 860) { e.preventDefault(); parentLi.classList.toggle('open'); } }); }); } /* ---------- WhatsApp floating widget ---------- */ const waFab = document.getElementById('waFab'); const waPopup = document.getElementById('waPopup'); const waPopupClose = document.getElementById('waPopupClose'); if (waFab && waPopup) { waFab.addEventListener('click', () => waPopup.classList.toggle('open')); waPopupClose?.addEventListener('click', () => waPopup.classList.remove('open')); document.addEventListener('click', (e) => { if (!document.getElementById('waWidget').contains(e.target)) { waPopup.classList.remove('open'); } }); } /* ---------- Animated counters (Hero stats) ---------- */ const counters = document.querySelectorAll('[data-counter]'); if (counters.length) { const counterObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (!entry.isIntersecting) return; const el = entry.target; const target = parseInt(el.dataset.counter, 10); const suffix = el.dataset.suffix || ''; const duration = 1600; const start = performance.now(); function tick(now) { const progress = Math.min((now - start) / duration, 1); const eased = 1 - Math.pow(1 - progress, 3); el.textContent = Math.floor(eased * target) + suffix; if (progress < 1) requestAnimationFrame(tick); else el.textContent = target + suffix; } requestAnimationFrame(tick); counterObserver.unobserve(el); }); }, { threshold: 0.4 }); counters.forEach(c => counterObserver.observe(c)); } /* ---------- Swiper-style carousels (certificates, testimonials, history, team) ---------- */ document.querySelectorAll('[data-swiper]').forEach(wrap => { const track = wrap.querySelector('.swiper-track'); const prevBtn = wrap.querySelector('.swiper-btn.prev'); const nextBtn = wrap.querySelector('.swiper-btn.next'); if (!track) return; function updateButtons() { const items = track.querySelectorAll('.card-item').length; const minToShow = parseInt(wrap.dataset.minToShow || '3', 10); const showNav = items > minToShow; if (prevBtn) prevBtn.style.display = showNav ? 'flex' : 'none'; if (nextBtn) nextBtn.style.display = showNav ? 'flex' : 'none'; track.classList.toggle('is-centered', !showNav); } updateButtons(); function scrollByCard(dir) { const card = track.querySelector('.card-item'); const gap = 20; const cardWidth = card ? card.getBoundingClientRect().width + gap : 300; track.scrollBy({ left: dir * cardWidth, behavior: 'smooth' }); } prevBtn?.addEventListener('click', () => scrollByCard(-1)); nextBtn?.addEventListener('click', () => scrollByCard(1)); }); /* ---------- Image popup modal (certificates, maklumat layanan) ---------- */ const imgModal = document.getElementById('imageModal'); if (imgModal) { const imgModalPic = imgModal.querySelector('img'); document.querySelectorAll('[data-modal-img]').forEach(trigger => { trigger.addEventListener('click', () => { imgModalPic.src = trigger.dataset.modalImg; imgModal.classList.add('open'); }); }); imgModal.querySelector('.modal-close')?.addEventListener('click', () => imgModal.classList.remove('open')); imgModal.addEventListener('click', (e) => { if (e.target === imgModal) imgModal.classList.remove('open'); }); } /* ---------- Generic PDF preview modal ---------- */ const pdfModal = document.getElementById('pdfModal'); if (pdfModal) { const pdfFrame = pdfModal.querySelector('iframe'); document.querySelectorAll('[data-modal-pdf]').forEach(trigger => { trigger.addEventListener('click', (e) => { e.preventDefault(); pdfFrame.src = trigger.dataset.modalPdf; pdfModal.classList.add('open'); }); }); pdfModal.querySelector('.modal-close')?.addEventListener('click', () => { pdfModal.classList.remove('open'); pdfFrame.src = ''; }); } /* ---------- Accordion (FAQ, Karir & Rekrutmen) ---------- */ document.querySelectorAll('.accordion-header').forEach(header => { header.addEventListener('click', () => { const item = header.closest('.accordion-item'); const group = item.closest('[data-accordion-group]'); if (group && group.dataset.accordionGroup === 'single') { group.querySelectorAll('.accordion-item.open').forEach(openItem => { if (openItem !== item) openItem.classList.remove('open'); }); } item.classList.toggle('open'); }); }); /* ---------- Tabs (Alat Ukur/Bantu, Kantor Wilayah/Area, Berita kategori, Direksi jabatan) ---------- */ document.querySelectorAll('[data-tabs]').forEach(tabGroup => { const buttons = tabGroup.querySelectorAll('.tab-btn'); const targetSelector = tabGroup.dataset.tabs; buttons.forEach(btn => { btn.addEventListener('click', () => { buttons.forEach(b => b.classList.remove('active')); btn.classList.add('active'); document.querySelectorAll(targetSelector + ' [data-tab-panel]').forEach(panel => { panel.style.display = panel.dataset.tabPanel === btn.dataset.tabValue ? '' : 'none'; }); }); }); }); /* ---------- Video Gallery: main player + playlist switch (Beranda & Media Publikasi) ---------- */ document.querySelectorAll('[data-video-gallery]').forEach(gallery => { const mainFrame = gallery.querySelector('.video-main iframe'); const mainCaption = gallery.querySelector('.video-main .caption'); gallery.querySelectorAll('.video-playlist-item').forEach(item => { item.addEventListener('click', () => { const videoId = item.dataset.videoId; if (mainFrame) mainFrame.src = 'https://www.youtube.com/embed/' + videoId + '?autoplay=1'; if (mainCaption) mainCaption.textContent = item.dataset.videoTitle || ''; gallery.querySelectorAll('.video-playlist-item').forEach(i => i.classList.remove('active')); item.classList.add('active'); }); }); }); /* ---------- "Muat Lebih Banyak" pagination (Berita, Galeri) ---------- */ document.querySelectorAll('[data-load-more]').forEach(btn => { btn.addEventListener('click', () => { const targetList = document.querySelector(btn.dataset.loadMore); if (!targetList) return; const hiddenItems = targetList.querySelectorAll('.is-hidden'); const batch = parseInt(btn.dataset.batch || '6', 10); Array.from(hiddenItems).slice(0, batch).forEach(el => el.classList.remove('is-hidden')); if (targetList.querySelectorAll('.is-hidden').length === 0) btn.style.display = 'none'; }); }); /* ---------- Star rating input (Survey Kepuasan Pelanggan) ---------- */ document.querySelectorAll('[data-star-rating]').forEach(group => { const stars = group.querySelectorAll('.star'); const input = group.querySelector('input[type="hidden"]'); const counterLabel = group.querySelector('.star-count'); function setRating(value) { stars.forEach((s, i) => s.classList.toggle('filled', i < value)); if (input) input.value = value; if (counterLabel) counterLabel.textContent = value; } stars.forEach((star, index) => { star.addEventListener('click', () => setRating(index + 1)); }); }); /* ---------- Simple client-side validation feedback for forms ---------- */ document.querySelectorAll('form[data-validate]').forEach(form => { form.addEventListener('submit', (e) => { let valid = true; form.querySelectorAll('[required]').forEach(field => { if (!field.value.trim()) { valid = false; field.style.borderColor = 'var(--c-danger)'; } else { field.style.borderColor = ''; } }); if (!valid) e.preventDefault(); }); }); });