1// Product Quantity. 2function productQuantity(container = document) { 3 container.querySelectorAll('.eab-quantity-input').forEach((input) => { 4 input.addEventListener('change', () => { 5 const wrapper = input.closest('.eab-product-cart-wrapper'); 6 if (!wrapper) { 7 return; 8 } 9 10 const button = wrapper.querySelector('.eab-add-to-cart'); 11 if (!button) { 12 return; 13 } 14 15 const quantity = parseInt(input.value, 10) || 1; 16 button.dataset.quantity = quantity; 17 }); 18 }); 19} 20 21// SIDEBAR TABS ACCORDION BLOCK INIT. 22document.addEventListener('DOMContentLoaded', () => { 23 const tabsBlocks = document.querySelectorAll('.sp-eab-sidebar-tabs'); 24 if (tabsBlocks?.length > 0) { 25 tabsBlocks.forEach((tabAccordion) => { 26 const options = tabAccordion.getAttribute('data-tab-settings'); 27 let parsedOptions = {}; 28 if (options && options.trim()) { 29 try { 30 parsedOptions = JSON.parse(options); 31 } catch (e) { 32 // Invalid JSON, use empty object 33 parsedOptions = {}; 34 } 35 } 36 new EabTabAccordion(tabAccordion, parsedOptions); 37 }); 38 } 39}); 40 41document.addEventListener('DOMContentLoaded', () => { 42 const accordionWrappers = document.querySelectorAll( 43 '.sp-eab-regular-accordion,.sp-eab-post-accordion,.sp-eab-product-accordion' 44 ); 45 46 if (!accordionWrappers.length) { 47 return; 48 } 49 50 accordionWrappers.forEach((accordionBlock) => { 51 const qs = (s) => accordionBlock.querySelector(s); 52 const qsa = (s) => accordionBlock.querySelectorAll(s); 53 54 /* ------------------------- 55 * ACCORDION INIT 56 * ------------------------- */ 57 const initAccordion = () => { 58 const el = qs('.sp-eab-accordion'); 59 if (!el) { 60 return null; 61 } 62 63 let options = {}; 64 const attrOptions = el.getAttribute('data-accordion-settings'); 65 if (attrOptions && attrOptions.trim()) { 66 try { 67 options = JSON.parse(attrOptions); 68 } catch (e) { 69 // Invalid JSON, use empty object 70 options = {}; 71 } 72 } 73 const accordion = new EabAccordion(el, options); 74 75 return accordion; 76 }; 77 78 let accordion = initAccordion(); 79 }); 80}); 81 82 83//Image effect. 84const applyEffectClasses = (item, isActive) => { 85 const effectType = item.dataset.imageEffect; 86 const hoverGrayScale = item.dataset.hoverGrayScale; 87 const bgEl = item.querySelector( 88 '.sp-eab-accordion-bg,.sp-eab-featured-image-wrapper' 89 ); 90 91 if (!effectType || !bgEl) { 92 return; 93 } 94 95 // Remove all effect classes 96 item.classList.remove( 97 'eab-zoom-out-active', 98 'eab-zoom-out-normal', 99 'eab-zoom-out-onhover' 100 ); 101 102 const useHoverGray = hoverGrayScale && !isActive; 103 104 let effectClass = ''; 105 106 switch (effectType) { 107 case 'zoomOut': 108 if (useHoverGray) { 109 effectClass = 'eab-zoom-out-normal eab-zoom-out-onhover'; 110 } else if (isActive) { 111 effectClass = 'eab-zoom-out-active'; 112 } else { 113 effectClass = 'eab-zoom-out-normal'; 114 } 115 break; 116 default: 117 effectClass = ''; 118 } 119 120 // Apply classes 121 if (effectClass) { 122 effectClass.split(' ').forEach((cls) => item.classList.add(cls)); 123 } 124}; 125 126const getDeviceValuePx = (valueObj, device = 'Desktop', units = false) => { 127 if (!valueObj || !valueObj.device || !valueObj.unit) { 128 return 0; 129 } 130 131 const value = valueObj.device[device]; 132 const unit = valueObj.unit[device]; 133 134 if (value === null) { 135 return 0; 136 } 137 138 // Return proper string with correct unit 139 return unit === '%' && units ? `${value}%` : value; 140}; 141 142// preloader init. 143document.addEventListener('DOMContentLoaded', () => { 144 const accordionBlocks = document.querySelectorAll( 145 '.sp-easy-accordion-block' 146 ); 147 if (accordionBlocks.length === 0) { 148 return; 149 } 150 accordionBlocks?.forEach((accordion) => { 151 /** 152 * Preloader. 153 * Fades out preloader. 154 */ 155 const preloader = accordion?.querySelector('.sp-eab-preloader'); 156 if (preloader) { 157 // Wait 0.5 seconds before showing fallback. 158 setTimeout(() => { 159 preloader.classList.remove('sp-d-block'); 160 preloader.classList.add('sp-d-hidden'); 161 accordion.classList.add('sp-eab-preloader-removed'); 162 }, 500); 163 } 164 }); 165}); 166 167document.addEventListener('DOMContentLoaded', () => { 168 const accordions = Array.from( 169 document.querySelectorAll( 170 '.sp-eab-image-accordion,.sp-eab-product-accordion' 171 ) 172 ); 173 174 accordions.forEach((accordion) => { 175 const items = Array.from( 176 accordion.querySelectorAll('.sp-eab-image-accordion-item') 177 ); 178 if (!items.length) { 179 return; 180 } 181 182 // --- Read data attributes --- 183 const defaultOpen = accordion.dataset.defaultOpen || 'first-item';
184 const activeEvent = accordion.dataset.activeEvent || 'click'; 185 const selectedIndex = 186 parseInt(accordion.dataset.selectedAccordion, 10) - 1; 187 const scrollToActive = accordion.dataset.scrollToActiveItem; 188 const accessibility = accordion.dataset.eabAccessibility; 189 const itemToUrl = accordion.dataset.anchorLink; 190 const autoInterval = accordion.dataset.autoplayDelay; 191 const animation = 192 accordion.dataset.animation && 193 accordion.dataset.animation !== 'none' 194 ? accordion.dataset.animation 195 : null; 196 197 let activeIndex = -1; 198 let intervalRef = null; 199 200 const applyAnimation = (item, isActive) => { 201 const content = item.querySelector('.eab-animation'); 202 if (content) { 203 // Only apply animation if it's not 'none' 204 if (animation && animation !== 'none') { 205 // Remove previous animation classes 206 content.classList.remove('animated', animation); 207 if (isActive) { 208 content.classList.add('animated', animation); 209 } 210 } 211 } 212 }; 213 214 const updateAccessibility = () => { 215 if (!accessibility) { 216 return; 217 } 218 items.forEach((item, index) => { 219 const isActive = index === activeIndex; 220 const button = item.querySelector('.sp-eab-accordion-bg'); 221 222 item.setAttribute('role', 'region'); 223 if (button) { 224 button.setAttribute('role', 'button'); 225 button.setAttribute('tabindex', '0'); 226 button.setAttribute( 227 'aria-expanded', 228 isActive ? 'true' : 'false' 229 ); 230 button.setAttribute( 231 'aria-label', 232 ( 233 item.querySelector('.sp-eab-image-title') 234 ?.textContent || '' 235 ) 236 .replace(/\s+/g, ' ') 237 .trim() 238 ); 239 } 240 }); 241 }; 242 243 // --- Helper: set active item --- 244 let allowUrlUpdate = false; // URL updates blocked until first open 245 246 const setActiveItem = (index, shouldScroll = false) => { 247 items.forEach((item, i) => { 248 const isActive = i === index; 249 if ( 250 !( 251 accordion.classList.contains( 252 'sp-eab-accordion-slider' 253 ) || accordion.classList.contains('sp-eab-carousel') 254 ) 255 ) { 256 item.classList.toggle('active', isActive); 257 } 258 applyEffectClasses(item, isActive); 259 applyAnimation(item, isActive); 260 }); 261 262 const previousIndex = activeIndex; 263 activeIndex = index; 264 updateAccessibility(); 265 266 // --- URL update logic --- 267 const activeItem = items[index]; 268 if (activeItem && itemToUrl) { 269 const slug = activeItem.getAttribute('data-slug'); 270 if (slug && allowUrlUpdate && previousIndex !== index) { 271 const base = window.location.href.split('#')[0]; 272 history.replaceState(null, '', base + slug); 273 } 274 } 275 276 // Scroll 277 if (shouldScroll && scrollToActive && items[index]) { 278 items[index].scrollIntoView({ 279 behavior: 'smooth', 280 block: 'center', 281 inline: 'nearest', 282 }); 283 } 284 285 // After first active item: allow URL updates 286 allowUrlUpdate = true; 287 }; 288 289 // --- Keyboard navigation --- 290 if (accessibility) { 291 items.forEach((item, index) => { 292 const button = item.querySelector('.sp-eab-accordion-bg'); 293 if (!button) { 294 return; 295 } 296 297 button.addEventListener('keydown', (e) => { 298 switch (e.key) { 299 case 'ArrowRight': 300 case 'ArrowDown': 301 setActiveItem( 302 (activeIndex + 1) % items.length, 303 true 304 ); 305 items[activeIndex % items.length] 306 .querySelector('.sp-eab-accordion-bg') 307 ?.focus(); 308 e.preventDefault(); 309 break; 310 case 'ArrowLeft': 311 case 'ArrowUp': 312 setActiveItem( 313 (activeIndex - 1 + items.length) % items.length, 314 true 315 ); 316 items[activeIndex % items.length] 317 .querySelector('.sp-eab-accordion-bg') 318 ?.focus(); 319 e.preventDefault(); 320 break; 321 case 'Enter': 322 case ' ': 323 setActiveItem(index, true); 324 e.preventDefault(); 325 break; 326 } 327 }); 328 }); 329 } 330 331 let isHashOpen = false; 332 const currentHash = window.location.hash; 333 334 if (currentHash && itemToUrl) { 335 const matchedIndex = items.findIndex( 336 (item) => item.getAttribute('data-slug') === currentHash 337 ); 338 339 if (matchedIndex >= 0) { 340 isHashOpen = true; 341 activeIndex = matchedIndex; 342 343 // Open from URL but DO NOT update URL again 344 setTimeout(() => { 345 setActiveItem(matchedIndex, true); 346 }, 50); 347 } 348 } 349 350 if (!isHashOpen) { 351 switch (defaultOpen) { 352 case 'first-item': 353 activeIndex = 0; 354 break; 355 case 'close-all': 356 activeIndex = -1; 357 break; 358 case 'open-selected-item': 359 activeIndex = 360 selectedIndex >= 0 && selectedIndex < items.length 361 ? selectedIndex 362 : 0; 363 break; 364 default: 365 activeIndex = 0; 366 } 367
368 if (activeIndex >= 0) { 369 setTimeout(() => setActiveItem(activeIndex, true), 300); 370 } 371 } 372 373 // --- Auto-play logic --- 374 let autoPlayIntervalRef = null; 375 let isPaused = false; 376 377 // --- Start / Resume autoplay --- 378 const startAutoPlay = () => { 379 clearInterval(autoPlayIntervalRef); 380 if (items.length <= 1 || isPaused) { 381 return; 382 } 383 autoPlayIntervalRef = setInterval(() => { 384 const nextIndex = (activeIndex + 1) % items.length; 385 setActiveItem(nextIndex, true); 386 }, autoInterval); 387 }; 388 389 // --- Pause autoplay --- 390 const pauseAutoplay = () => { 391 isPaused = true; 392 clearInterval(autoPlayIntervalRef); 393 }; 394 395 // --- Resume autoplay --- 396 const resumeAutoplay = () => { 397 if (!isPaused) { 398 return; 399 } 400 isPaused = false; 401 startAutoPlay(); 402 }; 403 404 if (activeEvent === 'auto') { 405 startAutoPlay(); 406 accordion.addEventListener('mouseenter', pauseAutoplay); 407 accordion.addEventListener('mouseleave', resumeAutoplay); 408 } 409 410 // --- Click / Hover Event handling --- 411 const eventType = activeEvent === 'hover' ? 'mouseenter' : 'click'; 412 413 items.forEach((item, index) => { 414 item.addEventListener(eventType, () => { 415 if (defaultOpen === 'close-all' && activeIndex === index) { 416 // Only remove active class if NOT slider 417 if ( 418 !( 419 accordion.classList.contains( 420 'sp-eab-accordion-slider' 421 ) || accordion.classList.contains('sp-eab-carousel') 422 ) 423 ) { 424 item.classList.remove('active'); 425 } 426 applyEffectClasses(item, false); 427 activeIndex = -1; 428 updateAccessibility(); 429 } else { 430 setActiveItem(index, true); 431 } 432 433 // Restart autoplay if enabled 434 if (activeEvent === 'auto') { 435 startAutoPlay(); 436 } 437 }); 438 }); 439 }); 440 441 // Add scripts for variation. 442 productQuantity(); 443}); 444 445const animateAccordionItemsOnView = (items, animationClass = 'none') => { 446 if (!animationClass || animationClass.toLowerCase() === 'none') { 447 return; 448 } 449 if (!('IntersectionObserver' in window)) { 450 // Fallback: animate immediately if IntersectionObserver not supported 451 items.forEach((item) => { 452 item.classList.add('animated', animationClass); 453 }); 454 return; 455 } 456 457 const observer = new IntersectionObserver( 458 (entries, obs) => { 459 entries.forEach((entry) => { 460 if (entry.isIntersecting) { 461 entry.target.classList.add('animated', animationClass); 462 // Stop observing after animation 463 obs.unobserve(entry.target); 464 } 465 }); 466 }, 467 { 468 threshold: 0.2, // Trigger when 20% of the item is visible 469 } 470 ); 471 472 items.forEach((item) => observer.observe(item)); 473}; 474 475// reload screen on resize tablet-or-desktop to mobile. 476document.addEventListener('DOMContentLoaded', () => { 477 if (window?.elementorFrontend?.isEditMode()) { 478 return; 479 } 480 // Function to determine the device category. 481 const getDeviceType = () => { 482 const width = window.innerWidth; 483 if (width <= 600) { 484 return 'mobile'; 485 } 486 return 'tablet-or-desktop'; 487 }; 488 489 // Track initial device type 490 let currentDevice = getDeviceType(); 491 492 window.addEventListener('resize', () => { 493 const newDevice = getDeviceType(); 494 // Reload only if switching between mobile and tablet/desktop 495 if (newDevice !== currentDevice) { 496 location.reload(); 497 } 498 499 // Update the current device type 500 currentDevice = newDevice; 501 }); 502});
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.