1(function($) { 2 'use strict'; 3 4 // Member Logos Component 5 const MemberLogos = { 6 7 init: function() { 8 this.initAnimations(); 9 this.initLazyLoading(); 10 this.initAccessibility(); 11 this.initResponsive(); 12 }, 13 14 // Initialize scroll animations 15 initAnimations: function() { 16 const animatedItems = document.querySelectorAll('.member-logos-section .animate-item'); 17 18 if (animatedItems.length === 0) return; 19 20 // Check if AOS library is available, otherwise use custom implementation 21 if (typeof AOS !== 'undefined') { 22 AOS.init({ 23 duration: 600, 24 once: true, 25 offset: 100 26 }); 27 } else { 28 // Custom scroll animation implementation 29 const observerOptions = { 30 root: null, 31 rootMargin: '0px', 32 threshold: 0.1 33 }; 34 35 const observer = new IntersectionObserver((entries) => { 36 entries.forEach(entry => { 37 if (entry.isIntersecting) { 38 const delay = entry.target.dataset.aosDelay || 0; 39 setTimeout(() => { 40 entry.target.classList.add('aos-animate'); 41 }, delay); 42 observer.unobserve(entry.target); 43 } 44 }); 45 }, observerOptions); 46 47 animatedItems.forEach(item => { 48 observer.observe(item); 49 }); 50 } 51 }, 52 53 // Initialize lazy loading for logo images 54 initLazyLoading: function() { 55 const logoImages = document.querySelectorAll('.member-logos-section .member-logo'); 56 57 if ('IntersectionObserver' in window) { 58 const imageObserver = new IntersectionObserver((entries, observer) => { 59 entries.forEach(entry => { 60 if (entry.isIntersecting) { 61 const img = entry.target; 62 63 // Add loading animation 64 img.classList.add('loading'); 65 66 // Load the image 67 if (img.dataset.src) { 68 img.src = img.dataset.src; 69 img.removeAttribute('data-src'); 70 } 71 72 // Remove loading animation once loaded 73 img.addEventListener('load', function() { 74 img.classList.remove('loading'); 75 img.classList.add('loaded'); 76 }); 77 78 observer.unobserve(img); 79 } 80 }); 81 }, { 82 rootMargin: '50px' 83 }); 84 85 logoImages.forEach(img => { 86 if (img.dataset.src) { 87 imageObserver.observe(img); 88 } 89 }); 90 } 91 }, 92 93 // Initialize accessibility features 94 initAccessibility: function() { 95 const logoLinks = document.querySelectorAll('.member-logos-section .logo-item a'); 96 97 logoLinks.forEach(link => { 98 // Add keyboard navigation support 99 link.addEventListener('keydown', function(e) { 100 if (e.key === 'Enter' || e.key === ' ') { 101 e.preventDefault(); 102 this.click(); 103 } 104 }); 105 106 // Enhance focus styles 107 link.addEventListener('focus', function() { 108 this.closest('.logo-item').classList.add('has-focus'); 109 }); 110 111 link.addEventListener('blur', function() { 112 this.closest('.logo-item').classList.remove('has-focus'); 113 }); 114 }); 115 }, 116 117 // Initialize responsive behavior 118 initResponsive: function() { 119 const grids = document.querySelectorAll('.member-logos-section .logos-grid'); 120 121 grids.forEach(grid => { 122 this.updateGridLayout(grid); 123 124 // Update on window resize 125 let resizeTimer; 126 window.addEventListener('resize', () => { 127 clearTimeout(resizeTimer); 128 resizeTimer = setTimeout(() => { 129 this.updateGridLayout(grid); 130 }, 250); 131 }); 132 }); 133 }, 134 135 // Update grid layout based on screen size 136 updateGridLayout: function(grid) { 137 const width = window.innerWidth; 138 let columns; 139 140 if (width <= 479) { 141 // Mobile 142 columns = grid.dataset.mobileCols || '2'; 143 } else if (width <= 991) { 144 // Tablet 145 columns = grid.dataset.tabletCols || '3'; 146 } else { 147 // Desktop 148 columns = grid.dataset.desktopCols || '5'; 149 } 150 151 // Apply dynamic styling if needed 152 grid.style.setProperty('--grid-columns', columns); 153 }, 154 155 // Carousel functionality (if layout is carousel) 156 initCarousel: function() { 157 const carousels = document.querySelectorAll('.member-logos-section.layout-carousel .logos-grid'); 158
159 carousels.forEach(carousel => { 160 let isDown = false; 161 let startX; 162 let scrollLeft; 163 164 // Mouse drag functionality 165 carousel.addEventListener('mousedown', (e) => { 166 isDown = true; 167 carousel.classList.add('active'); 168 startX = e.pageX - carousel.offsetLeft; 169 scrollLeft = carousel.scrollLeft; 170 }); 171 172 carousel.addEventListener('mouseleave', () => { 173 isDown = false; 174 carousel.classList.remove('active'); 175 }); 176 177 carousel.addEventListener('mouseup', () => { 178 isDown = false; 179 carousel.classList.remove('active'); 180 }); 181 182 carousel.addEventListener('mousemove', (e) => { 183 if (!isDown) return; 184 e.preventDefault(); 185 const x = e.pageX - carousel.offsetLeft; 186 const walk = (x - startX) * 2; 187 carousel.scrollLeft = scrollLeft - walk; 188 }); 189 190 // Touch support 191 let touchStartX = 0; 192 let touchScrollLeft = 0; 193 194 carousel.addEventListener('touchstart', (e) => { 195 touchStartX = e.touches[0].pageX - carousel.offsetLeft; 196 touchScrollLeft = carousel.scrollLeft; 197 }); 198 199 carousel.addEventListener('touchmove', (e) => { 200 const x = e.touches[0].pageX - carousel.offsetLeft; 201 const walk = (x - touchStartX) * 2; 202 carousel.scrollLeft = touchScrollLeft - walk; 203 }); 204 }); 205 }, 206 207 // Filter functionality (optional feature) 208 initFilter: function() { 209 const filterButtons = document.querySelectorAll('.member-logos-filter button'); 210 const logoItems = document.querySelectorAll('.member-logos-section .logo-item'); 211 212 if (filterButtons.length === 0) return; 213 214 filterButtons.forEach(button => { 215 button.addEventListener('click', function() { 216 const filter = this.dataset.filter; 217 218 // Update active state 219 filterButtons.forEach(btn => btn.classList.remove('active')); 220 this.classList.add('active'); 221 222 // Filter items 223 logoItems.forEach(item => { 224 if (filter === 'all' || item.dataset.category === filter) { 225 item.style.display = ''; 226 setTimeout(() => { 227 item.classList.add('show'); 228 }, 10); 229 } else { 230 item.classList.remove('show'); 231 setTimeout(() => { 232 item.style.display = 'none'; 233 }, 300); 234 } 235 }); 236 }); 237 }); 238 }, 239 240 // Search functionality (optional feature) 241 initSearch: function() { 242 const searchInput = document.querySelector('.member-logos-search input'); 243 const logoItems = document.querySelectorAll('.member-logos-section .logo-item'); 244 245 if (!searchInput) return; 246 247 searchInput.addEventListener('input', function() { 248 const searchTerm = this.value.toLowerCase(); 249 250 logoItems.forEach(item => { 251 const companyName = item.querySelector('img').alt.toLowerCase(); 252 253 if (companyName.includes(searchTerm)) { 254 item.style.display = ''; 255 } else { 256 item.style.display = 'none'; 257 } 258 }); 259 }); 260 } 261 }; 262 263 // Initialize when DOM is ready 264 $(document).ready(function() { 265 MemberLogos.init(); 266 267 // Check for specific layout types 268 if ($('.member-logos-section.layout-carousel').length > 0) { 269 MemberLogos.initCarousel(); 270 } 271 272 // Check for filter functionality 273 if ($('.member-logos-filter').length > 0) { 274 MemberLogos.initFilter(); 275 } 276 277 // Check for search functionality 278 if ($('.member-logos-search').length > 0) { 279 MemberLogos.initSearch(); 280 } 281 }); 282 283 // Reinitialize on Oxygen Builder preview update 284 if (typeof angular !== 'undefined') { 285 angular.element(document).ready(function() { 286 const scope = angular.element('[ng-controller]').scope(); 287 if (scope) { 288 scope.$on('oxygen-ajax-element-loaded', function() { 289 setTimeout(function() { 290 MemberLogos.init(); 291 }, 100); 292 }); 293 } 294 }); 295 } 296 297})(jQuery);
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.