1/** 2 * Hero Parallax Effect 3 * Adds subtle parallax scrolling effect to hero background images 4 * Configuration can be adjusted via CSS custom properties or data attributes 5 */ 6 7(function (Drupal) { 8 'use strict'; 9 10 Drupal.behaviors.heroParallax = { 11 attach: function (context, settings) { 12 const heroSections = context.querySelectorAll('.hero-section'); 13 14 if (!heroSections.length) return; 15 16 // Default parallax configuration 17 const defaultParallaxSpeed = 0.15; 18 let ticking = false; 19 20 /** 21 * Get parallax speed from data attribute or use default 22 */ 23 function getParallaxSpeed(heroSection) { 24 const speed = heroSection.dataset.parallaxSpeed; 25 return speed ? parseFloat(speed) : defaultParallaxSpeed; 26 } 27 28 /** 29 * Update parallax position for a hero section 30 */ 31 function updateParallax(heroSection) { 32 const heroBackground = heroSection.querySelector('.hero-background'); 33 if (!heroBackground) return; 34 35 const rect = heroSection.getBoundingClientRect(); 36 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 37 const elementTop = rect.top + scrollTop; 38 const viewportHeight = window.innerHeight; 39 40 // Only apply parallax when element is in viewport 41 if (rect.top < viewportHeight && rect.bottom > 0) { 42 // Get parallax speed for this specific section 43 const parallaxSpeed = getParallaxSpeed(heroSection); 44 45 // Calculate parallax offset 46 const scrolled = scrollTop - elementTop + viewportHeight; 47 const parallaxOffset = scrolled * parallaxSpeed; 48 49 // Apply transform with 3D acceleration for better performance 50 heroBackground.style.transform = `translate3d(0, ${parallaxOffset}px, 0)`; 51 } 52 } 53 54 /** 55 * Request animation frame for smooth parallax 56 */ 57 function requestTick() { 58 if (!ticking) { 59 requestAnimationFrame(() => { 60 heroSections.forEach(updateParallax); 61 ticking = false; 62 }); 63 ticking = true; 64 } 65 } 66 67 // Initialize parallax on load 68 heroSections.forEach(updateParallax); 69 70 // Update parallax on scroll with throttling 71 window.addEventListener('scroll', requestTick, { passive: true }); 72 73 // Update parallax on resize 74 window.addEventListener('resize', () => { 75 requestTick(); 76 }, { passive: true }); 77 78 // Update parallax when carousel slides change 79 const carousels = context.querySelectorAll('.hero-carousel'); 80 carousels.forEach(carousel => { 81 carousel.addEventListener('slide.bs.carousel', () => { 82 setTimeout(() => { 83 const activeItem = carousel.querySelector('.carousel-item.active .hero-section'); 84 if (activeItem) { 85 updateParallax(activeItem); 86 } 87 }, 50); 88 }); 89 }); 90 91 // Cleanup function 92 context.heroParallaxCleanup = () => { 93 window.removeEventListener('scroll', requestTick); 94 window.removeEventListener('resize', requestTick); 95 }; 96 }, 97 98 detach: function (context, settings, trigger) { 99 if (trigger === 'unload' && context.heroParallaxCleanup) { 100 context.heroParallaxCleanup(); 101 } 102 } 103 }; 104 105})(Drupal);
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.