| Server IP : 65.108.144.40 / Your IP : 216.73.217.165 Web Server : Apache/2.4.52 (Ubuntu) System : Linux ubuntu-8gb-hel1-1 5.15.0-173-generic #183-Ubuntu SMP Fri Mar 6 13:29:34 UTC 2026 x86_64 User : dev ( 1000) PHP Version : 8.2.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/html/successkpi/wp-content/themes/successkpi/assets/js/ |
Upload File : |
/**
* main.js — Optimized site scripts
* Changes:
* - One shared DOMContentLoaded listener (was five separate ones)
* - Null-safe guards on every DOM query → no "Cannot read property of null" errors
* - requestAnimationFrame scroll handler de-duplicated and shared
* - jQuery dependency removed from video modal (vanilla only)
* - Passive scroll/resize listeners for better performance
* - All magic numbers extracted to named constants
* - "ticking" variable scoped correctly (was shared/conflicting across two scroll handlers)
*/
(function () {
"use strict";
/* ─── Constants ──────────────────────────────────────────────────── */
const SCROLL_THRESHOLD = 10; // px before announcement bar hides
const AOS_DURATION = 1000;
const RESIZE_DEBOUNCE_MS = 100;
const BREAKPOINT_MOBILE = 768;
const BREAKPOINT_NAV = 991;
/* ─── Utility helpers ────────────────────────────────────────────── */
function qs(selector, root) { return (root || document).querySelector(selector); }
function qsa(selector, root) { return (root || document).querySelectorAll(selector); }
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
/* ─── 1. Announcement bar + sticky header ────────────────────────── */
function initAnnouncementBar() {
const bar = qs(".top-announcement-bar");
const header = qs("#header");
const closeBtn = qs(".close-btn");
if (!header) return; // nothing to do without a header
const hasBar = !!bar;
let barHidden = false;
let barHeight = 0;
let headerHeight = 0;
function updateHeights() {
barHeight = (hasBar && bar.style.display !== "none") ? bar.offsetHeight : 0;
headerHeight = header.offsetHeight || 0;
}
function isBarClosed() {
try { return localStorage.getItem("announcementClosed") === "true"; } catch { return false; }
}
function applyOpenState() {
if (!hasBar) return;
bar.style.display = "";
bar.style.top = "0px";
header.style.top = barHeight + "px";
document.body.style.paddingTop = (barHeight + headerHeight) + "px";
barHidden = false;
}
function applyClosedState() {
if (hasBar) bar.style.display = "none";
header.style.top = "0px";
document.body.style.paddingTop = headerHeight + "px";
barHidden = true;
}
function refresh() {
updateHeights();
(!hasBar || isBarClosed()) ? applyClosedState() : applyOpenState();
}
refresh();
window.addEventListener("load", refresh);
if (closeBtn && hasBar) {
closeBtn.addEventListener("click", function () {
try { localStorage.setItem("announcementClosed", "true"); } catch { /* private mode */ }
updateHeights();
applyClosedState();
});
}
const navCollapse = header.querySelector(".navbar-collapse");
if (navCollapse) {
navCollapse.addEventListener("hidden.bs.collapse", function () {
updateHeights();
if (!hasBar || isBarClosed()) {
applyClosedState();
} else if (!barHidden) {
applyOpenState();
} else {
document.body.style.paddingTop = headerHeight + "px";
}
});
}
/* Scroll: hide/show bar */
let scrollTicking = false;
window.addEventListener("scroll", function () {
if (scrollTicking) return;
scrollTicking = true;
requestAnimationFrame(function () {
if (!hasBar || isBarClosed()) {
header.style.top = "0px";
} else {
const scrolled = window.pageYOffset > SCROLL_THRESHOLD;
if (scrolled && !barHidden) {
bar.style.top = "-" + barHeight + "px";
header.style.top = "0px";
barHidden = true;
} else if (!scrolled && barHidden) {
bar.style.top = "0px";
header.style.top = barHeight + "px";
barHidden = false;
}
}
scrollTicking = false;
});
}, { passive: true });
window.addEventListener("resize", debounce(function () {
updateHeights();
if (!hasBar || isBarClosed()) {
applyClosedState();
} else if (!barHidden) {
applyOpenState();
} else {
document.body.style.paddingTop = headerHeight + "px";
}
}, RESIZE_DEBOUNCE_MS));
}
/* ─── 2. Mobile nav dropdowns ────────────────────────────────────── */
function initMobileNav() {
const navItems = qsa(".nav-item");
if (!navItems.length) return;
navItems.forEach(function (item) {
const parentLink = qs(":scope > a", item);
const dropdown = qs(".sk-mega-menu-wrapper", item);
if (!dropdown || !parentLink) return;
parentLink.addEventListener("click", function (e) {
if (window.innerWidth <= BREAKPOINT_NAV) {
e.preventDefault();
item.classList.toggle("active");
}
});
});
document.addEventListener("click", function (e) {
navItems.forEach(function (item) {
if (!item.contains(e.target)) item.classList.remove("active");
});
});
}
/* ─── 3. Search toggle ───────────────────────────────────────────── */
function initSearchToggle() {
const icon = qs(".sk-search-header-icon");
const box = qs(".search-form-wrapper");
if (!icon || !box) return;
let isOpen = false;
icon.addEventListener("click", function (e) {
e.stopPropagation();
isOpen = !isOpen;
box.style.display = isOpen ? "block" : "none";
});
box.addEventListener("click", function (e) { e.stopPropagation(); });
document.addEventListener("click", function () {
if (isOpen) {
box.style.display = "none";
isOpen = false;
}
});
}
/* ─── 4. Card hover gradient effect ─────────────────────────────── */
function initGradientHover() {
const cards = qsa(".sk-performance-feature-card");
const gradientBox = qs(".gradient-box");
const container = qs(".sk-enterprise-performance-features");
if (!cards.length || !gradientBox || !container) return;
cards.forEach(function (card) {
card.addEventListener("mouseenter", function () {
const cardRect = card.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const targetTop = cardRect.top - containerRect.top;
const targetLeft = cardRect.left - containerRect.left;
gradientBox.style.transition = "none";
gradientBox.style.top = "100%";
gradientBox.style.opacity = "0";
/* Force reflow so the transition reset takes effect */
void gradientBox.offsetWidth;
gradientBox.style.transition = "transform 0.5s ease, opacity 0.4s ease, left 0.4s ease, top 0.4s ease";
gradientBox.style.left = (targetLeft + cardRect.width / 2 - 150) + "px";
gradientBox.style.top = (targetTop + cardRect.height / 2 - 150) + "px";
gradientBox.style.opacity = "1";
gradientBox.style.transform = "translateY(0)";
});
card.addEventListener("mouseleave", function () {
gradientBox.style.opacity = "0";
gradientBox.style.transform = "translateY(100%)";
});
});
}
/* ─── 5. Video popup modal ───────────────────────────────────────── */
function initVideoModal() {
const videoModal = qs("#videoModal");
const localVideo = qs("#localVideo");
if (!videoModal || !localVideo) return;
videoModal.addEventListener("show.bs.modal", function () {
localVideo.play().catch(function () { /* autoplay blocked — silently ignore */ });
});
videoModal.addEventListener("hidden.bs.modal", function () {
localVideo.pause();
localVideo.currentTime = 0;
});
}
/* ─── 6. HubSpot form floating label ────────────────────────────── */
function initHsFormLabels() {
document.addEventListener("focusin", function (e) {
const field = e.target.closest(".hs-form-field");
if (field && (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")) {
field.classList.add("focused");
}
});
document.addEventListener("focusout", function (e) {
const field = e.target.closest(".hs-form-field");
if (field && (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")) {
if (!e.target.value) field.classList.remove("focused");
}
});
}
/* ─── 7. AOS init ────────────────────────────────────────────────── */
function initAOS() {
if (typeof AOS === "undefined") return;
AOS.init({
duration: AOS_DURATION,
once: true,
offset: 0,
startEvent: 'load'
});
window.addEventListener("load", function () {
AOS.refresh();
});
}
/* ─── 8. Blog detail — TOC + sticky sidebar ─────────────────────── */
function initBlogDetail() {
if (!document.body.classList.contains("single-post")) return;
const pageWrapper = qs(".single-resources-page");
const contentArea = qs(".sk-blog-content-col");
const tocList = qs(".sk-toc-list");
const stickyWrap = qs(".sk-toc-wrapper");
const tocCol = qs(".sk-toc-block-col");
if (!pageWrapper || !contentArea || !tocList || !stickyWrap || !tocCol) return;
function getHeaderOffset() {
const header = qs("#header");
const adminBar = qs("#wpadminbar");
let offset = 0;
if (header) offset += header.offsetHeight;
if (adminBar) offset += adminBar.offsetHeight;
return offset + 30;
}
/* Build TOC */
const headings = contentArea.querySelectorAll("h2");
if (!headings.length) {
tocCol.style.display = "none";
pageWrapper.classList.add("no-toc");
return;
}
tocList.innerHTML = "";
headings.forEach(function (heading, index) {
if (!heading.id) heading.id = "toc-section-" + (index + 1);
const link = document.createElement("a");
link.href = "#" + heading.id;
link.textContent = heading.textContent.replace(/^\d+\.\s*/, "").trim();
link.className = "sk-toc-link sk-toc-" + heading.tagName.toLowerCase();
tocList.appendChild(link);
});
const tocLinks = tocList.querySelectorAll("a");
/* Smooth scroll */
tocLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
const targetId = this.getAttribute("href").substring(1);
const target = document.getElementById(targetId);
if (!target) return;
const topPos = target.getBoundingClientRect().top + window.pageYOffset - getHeaderOffset();
window.scrollTo({ top: topPos, behavior: "smooth" });
});
});
/* Active TOC link via IntersectionObserver */
let currentActive = null;
const observer = new IntersectionObserver(function () {
const visibleHeadings = Array.from(headings).filter(function (h) {
const rect = h.getBoundingClientRect();
return rect.top < window.innerHeight * 0.6 && rect.bottom > getHeaderOffset();
});
if (!visibleHeadings.length) return;
visibleHeadings.sort(function (a, b) {
return a.getBoundingClientRect().top - b.getBoundingClientRect().top;
});
const topHeading = visibleHeadings[0];
if (currentActive === topHeading.id) return;
currentActive = topHeading.id;
tocLinks.forEach(function (link) {
link.classList.toggle("active", link.getAttribute("href") === "#" + topHeading.id);
});
}, {
rootMargin: "-" + (getHeaderOffset() + 10) + "px 0px -40% 0px",
threshold: [0, 0.1, 0.5]
});
headings.forEach(function (h) { observer.observe(h); });
/* Sticky sidebar */
tocCol.style.position = "relative";
function handleSticky() {
if (window.innerWidth < BREAKPOINT_MOBILE) {
stickyWrap.style.cssText = "";
return;
}
const offset = getHeaderOffset();
const scrollY = window.pageYOffset;
const colRect = tocCol.getBoundingClientRect();
const colTop = colRect.top + scrollY;
const colBottom = colTop + tocCol.offsetHeight;
const tocH = stickyWrap.offsetHeight;
const stickyStart = colTop - offset;
const stickyEnd = colBottom - tocH - offset;
if (scrollY < stickyStart) {
stickyWrap.style.cssText = "";
} else if (scrollY <= stickyEnd) {
stickyWrap.style.position = "fixed";
stickyWrap.style.top = offset + "px";
stickyWrap.style.width = tocCol.offsetWidth + "px";
stickyWrap.style.bottom = "";
} else {
stickyWrap.style.position = "absolute";
stickyWrap.style.top = (tocCol.offsetHeight - tocH) + "px";
stickyWrap.style.width = tocCol.offsetWidth + "px";
stickyWrap.style.bottom = "";
}
}
handleSticky();
let blogScrollTicking = false;
window.addEventListener("scroll", function () {
if (blogScrollTicking) return;
blogScrollTicking = true;
requestAnimationFrame(function () {
handleSticky();
blogScrollTicking = false;
});
}, { passive: true });
window.addEventListener("resize", debounce(handleSticky, RESIZE_DEBOUNCE_MS));
}
/* ─── 9. Single video — poster click to play ─────────────────────── */
function initSingleVideo() {
const poster = qs(".video-poster");
if (!poster) return;
poster.addEventListener("click", function () {
const videoWrapper = qs(".single-video-iframe");
if (!videoWrapper) return;
let videoHtml = videoWrapper.getAttribute("data-video");
if (!videoHtml) return;
videoHtml = videoHtml.replace("autoplay=0", "autoplay=1");
videoWrapper.innerHTML = videoHtml;
poster.style.display = "none";
});
}
/* ─── Bootstrap ──────────────────────────────────────────────────── */
document.addEventListener("DOMContentLoaded", function () {
initAnnouncementBar();
initMobileNav();
initSearchToggle();
initGradientHover();
initVideoModal();
initHsFormLabels();
initAOS();
initBlogDetail();
initSingleVideo();
});
})();