/**
* Main JavaScript file for Popular Computer Institute website
*/
// Document Ready Function
document.addEventListener('DOMContentLoaded', function() {
// Hide preloader when page is loaded
const preloader = document.querySelector('.preloader');
if (preloader) {
preloader.style.display = 'none';
}
// Initialize Back to Top button
initBackToTop();
// Initialize dropdown menus
initDropdowns();
// Add active class to nav items based on current page
highlightActiveNavItem();
// Initialize image fallbacks
initImageFallbacks();
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if (targetId === '#') return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
targetElement.scrollIntoView({
behavior: 'smooth'
});
}
});
});
// Counter animation for statistics
const counters = document.querySelectorAll('.counter');
if (counters.length > 0) {
const observerOptions = {
threshold: 0.5
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const counter = entry.target;
const target = parseInt(counter.getAttribute('data-target'));
const duration = 2000; // 2 seconds
const step = Math.ceil(target / (duration / 16)); // 60fps
let current = 0;
const updateCounter = () => {
current += step;
if (current > target) current = target;
counter.textContent = current.toLocaleString();
if (current < target) {
requestAnimationFrame(updateCounter);
}
};
updateCounter();
observer.unobserve(counter);
}
});
}, observerOptions);
counters.forEach(counter => {
observer.observe(counter);
});
}
// Mobile menu toggle
const navbarToggler = document.querySelector('.navbar-toggler');
if (navbarToggler) {
navbarToggler.addEventListener('click', function() {
document.body.classList.toggle('nav-open');
});
}
// Lazy loading images
if ('loading' in HTMLImageElement.prototype) {
// Browser supports native lazy loading
const lazyImages = document.querySelectorAll('img[loading="lazy"]');
lazyImages.forEach(img => {
img.src = img.dataset.src;
});
} else {
// Fallback for browsers that don't support native lazy loading
const lazyImages = document.querySelectorAll('.lazy-image');
if (lazyImages.length > 0) {
const lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove('lazy-image');
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(lazyImage => {
lazyImageObserver.observe(lazyImage);
});
}
}
// Initialize tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Hero Slider Functionality
initHeroSlider();
// Initialize particles for hero slider
createParticles();
// Handle image loading errors
handleImageErrors();
// Initialize counters for stats
initCounters();
// Mobile menu toggle
initMobileMenu();
});
/**
* Initialize Back to Top button
*/
function initBackToTop() {
const backToTopButton = document.querySelector('.back-to-top');
if (backToTopButton) {
// Show/hide button based on scroll position
window.addEventListener('scroll', function() {
if (window.pageYOffset > 300) {
backToTopButton.classList.add('show');
} else {
backToTopButton.classList.remove('show');
}
});
// Scroll to top when button is clicked
backToTopButton.addEventListener('click', function(e) {
e.preventDefault();
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
}
}
/**
* Initialize dropdown menus
*/
function initDropdowns() {
const dropdownToggles = document.querySelectorAll('.dropdown-toggle');
dropdownToggles.forEach(toggle => {
toggle.addEventListener('click', function(e) {
e.preventDefault();
const parent = this.parentElement;
const dropdown = parent.querySelector('.dropdown-menu');
// Toggle dropdown
dropdown.classList.toggle('show');
// Close dropdown when clicking outside
document.addEventListener('click', function closeDropdown(e) {
if (!parent.contains(e.target)) {
dropdown.classList.remove('show');
document.removeEventListener('click', closeDropdown);
}
});
});
});
}
/**
* Highlight active navigation item
*/
function highlightActiveNavItem() {
const currentLocation = location.pathname;
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
navLinks.forEach(link => {
if (link.getAttribute('href') === currentLocation) {
link.classList.add('active');
} else {
link.classList.remove('active');
}
});
}
/**
* Initialize image fallbacks
*/
function initImageFallbacks() {
const slideImages = document.querySelectorAll('.slide-image');
slideImages.forEach(img => {
const fallbackUrl = img.getAttribute('data-fallback');
if (fallbackUrl) {
const mainImage = new Image();
mainImage.onload = function() {
// Main image loaded successfully
};
mainImage.onerror = function() {
// Main image failed to load, use fallback
img.style.backgroundImage = `url('${fallbackUrl}')`;
};
// Extract the URL from the background-image style
const bgUrl = getComputedStyle(img).backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/i, '$1');
mainImage.src = bgUrl;
}
});
}
// Initialize tooltips
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function(tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Initialize popovers
const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTriggerList.map(function(popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
// Animate stats counter
function animateStats() {
const statElements = document.querySelectorAll('.stat-number');
statElements.forEach(function(stat) {
const target = parseInt(stat.getAttribute('data-count'));
const duration = 2000; // 2 seconds
const step = target / (duration / 16); // 60fps
let current = 0;
const updateCounter = function() {
current += step;
if (current < target) {
stat.textContent = Math.ceil(current).toLocaleString();
requestAnimationFrame(updateCounter);
} else {
stat.textContent = target.toLocaleString();
}
};
updateCounter();
});
}
// Check if element is in viewport
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// Handle scroll animations
function handleScrollAnimations() {
const statsSection = document.querySelector('.stats-section');
if (statsSection && isInViewport(statsSection)) {
animateStats();
// Remove event listener after animation starts
window.removeEventListener('scroll', handleScrollAnimations);
}
}
// Add scroll event listener
window.addEventListener('scroll', handleScrollAnimations);
// Also check on page load
handleScrollAnimations();
// Testimonial slider initialization
if (typeof Slick !== 'undefined') {
$('.testimonial-slider').slick({
dots: true,
infinite: true,
speed: 300,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 5000,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 600,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
});
}
// Hero Slider
function initHeroSlider() {
const slides = document.querySelectorAll('.slide');
const dots = document.querySelectorAll('.slider-dot');
const prevBtn = document.querySelector('.slider-prev');
const nextBtn = document.querySelector('.slider-next');
let currentSlide = 0;
let slideInterval;
// Function to show a specific slide
function showSlide(index) {
// Hide all slides
slides.forEach(slide => {
slide.classList.remove('active');
});
// Remove active class from all dots
dots.forEach(dot => {
dot.classList.remove('active');
});
// Show the current slide and dot
slides[index].classList.add('active');
dots[index].classList.add('active');
// Update current slide index
currentSlide = index;
}
// Function to show the next slide
function nextSlide() {
let next = currentSlide + 1;
if (next >= slides.length) {
next = 0;
}
showSlide(next);
}
// Function to show the previous slide
function prevSlide() {
let prev = currentSlide - 1;
if (prev < 0) {
prev = slides.length - 1;
}
showSlide(prev);
}
// Start automatic slideshow
function startSlideshow() {
slideInterval = setInterval(nextSlide, 5000);
}
// Stop automatic slideshow
function stopSlideshow() {
clearInterval(slideInterval);
}
// Event listeners for navigation
if (prevBtn) {
prevBtn.addEventListener('click', function() {
prevSlide();
stopSlideshow();
startSlideshow();
});
}
if (nextBtn) {
nextBtn.addEventListener('click', function() {
nextSlide();
stopSlideshow();
startSlideshow();
});
}
// Add click event to dots
dots.forEach((dot, index) => {
dot.addEventListener('click', function() {
showSlide(index);
stopSlideshow();
startSlideshow();
});
});
// Start the slideshow if there are slides
if (slides.length > 0) {
startSlideshow();
}
}
// Create particles for hero slider background
function createParticles() {
const sliderBg = document.querySelector('.slider-bg');
if (!sliderBg) return;
// Create 50 particles
for (let i = 0; i < 50; i++) {
const particle = document.createElement('div');
particle.classList.add('particle');
// Random size between 5px and 20px
const size = Math.random() * 15 + 5;
// Random position
const x = Math.random() * 100 - 50 + '%';
const y = Math.random() * 100 - 50 + '%';
// Random animation duration and delay
const duration = Math.random() * 10 + 5 + 's';
const delay = Math.random() * 5 + 's';
// Set CSS variables
particle.style.setProperty('--size', size + 'px');
particle.style.setProperty('--x', x);
particle.style.setProperty('--y', y);
particle.style.setProperty('--duration', duration);
particle.style.setProperty('--delay', delay);
sliderBg.appendChild(particle);
}
}
// Handle image loading errors
function handleImageErrors() {
const slideImages = document.querySelectorAll('.slide-image');
slideImages.forEach(img => {
// Check if the background image fails to load
const url = getComputedStyle(img).backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/i, '$1');
const fallback = img.getAttribute('data-fallback');
if (url && fallback) {
const testImg = new Image();
testImg.onerror = function() {
img.style.backgroundImage = `url('${fallback}')`;
};
testImg.src = url;
}
});
}
// Initialize counters for stats
function initCounters() {
const statValues = document.querySelectorAll('.stat-value');
if (statValues.length === 0) return;
// Check if element is in viewport
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// Animate counter
function animateCounter(element, target) {
let current = 0;
const increment = target / 100;
const duration = 2000; // 2 seconds
const interval = duration / 100;
const timer = setInterval(() => {
current += increment;
element.textContent = Math.round(current);
if (current >= target) {
element.textContent = target;
clearInterval(timer);
}
}, interval);
}
// Start animation when element is in viewport
function checkCounters() {
statValues.forEach(value => {
if (isInViewport(value) && !value.classList.contains('counted')) {
const target = parseInt(value.getAttribute('data-count') || value.textContent);
animateCounter(value, target);
value.classList.add('counted');
}
});
}
// Check on scroll
window.addEventListener('scroll', checkCounters);
// Check on page load
checkCounters();
}
// Mobile menu toggle
function initMobileMenu() {
const menuToggle = document.querySelector('.mobile-menu-toggle');
const mobileMenu = document.querySelector('.mobile-menu');
if (!menuToggle || !mobileMenu) return;
menuToggle.addEventListener('click', function() {
mobileMenu.classList.toggle('active');
this.classList.toggle('active');
});
}