1(function ($) { 2 // Initialize the flag to control animations 3 let runAnimations = true; 4 5 Drupal.behaviors.gsapContent = { 6 attach: function (context, settings) { 7 // Register Plugin 8 if (gsap && gsap.registerPlugin && ScrollTrigger) { 9 gsap.registerPlugin(ScrollTrigger); 10 } else { 11 console.error('GSAP or ScrollTrigger not available.'); 12 } 13 14 // Removes gsap animation from carousels inside tab/accordion components 15 const tabbedComponent = document.querySelectorAll('.coh-accordion-tabs-content'); 16 17 tabbedComponent.forEach((element) => { 18 const tabCarouselItems = element.querySelectorAll('.gsap-carousel-item'); 19 tabCarouselItems.forEach((element) => { 20 element.classList.remove("gsap-carousel-item"); 21 }); 22 }); 23 24 // Defines elements to be animated 25 const elements = { 26 featureBlockTextFirst: gsap.utils.toArray('.feature-block-component[data-content-order="text-first"]'), 27 featureBlockImageFirst: gsap.utils.toArray('.feature-block-component[data-content-order="image-first"]'), 28 pageHeaderComponent: gsap.utils.toArray('.page-header-component'), 29 fiftyFiftyComponent: gsap.utils.toArray('.fifty-fifty-component'), 30 listingComponent: gsap.utils.toArray('.listing-component:not([gsap-animation="disabled"]'), 31 pageHeroComponent: gsap.utils.toArray('.page-hero-component'), 32 pdpFadeInSection: gsap.utils.toArray('.gsap-fadein-section'), 33 pdpGalleryFadeInContainer: gsap.utils.toArray('.gsap-fadein-sku-gallery-container'), 34 carouselContainer: gsap.utils.toArray('.sbd-carousel'), 35 carouselItem: gsap.utils.toArray('.gsap-carousel-item'), 36 richTextFadeIn: gsap.utils.toArray('div:not(.coh-modal-inner):not(.coh-accordion-tabs-content) > .gsap-fadein-richtext:not([gsap-animation="disabled"])'), 37 toolboxItem: gsap.utils.toArray('#block-mytoolbox .items-list-wrapper .items-list') 38 }; 39 40 // Elements to reset on mobile or when reduced motion is enabled 41 const elementsToSetOpacity = Object.values(elements).flat(); 42 43 // Running animations only if the viewport is below 1024px 44 let isMobile = window.innerWidth <= 1024; 45 let reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; 46 47 // Initial check for media query and reduced motion 48 handleMediaQueryChange(); 49 50 // Add listener for future changes 51 window.addEventListener('resize', () => { 52 // Update isMobile on window resize 53 isMobile = window.innerWidth <= 1024; 54 handleMediaQueryChange(); 55 }); 56 57 // Add listener for reduce motion preference change 58 window.matchMedia("(prefers-reduced-motion: reduce)").addEventListener('change', (event) => { 59 // Update reduceMotion on preference change 60 reduceMotion = event.matches; 61 handleMediaQueryChange(); 62 }); 63 64 // Handle page show event for browser back button 65 window.addEventListener('pageshow', (event) => { 66 if (event.persisted) { 67 // Page was loaded from the back/forward cache 68 resetCarouselAnimations(); 69 handleMediaQueryChange(); 70 } 71 }); 72 73 function handleMediaQueryChange() { 74 if (!isMobile && !reduceMotion && runAnimations) { 75 // Animations when text is displayed first 76 elements.featureBlockTextFirst.forEach((element) => { 77 animateFeatureBlock(element, 50, 0); 78 }); 79 80 // Animations when image is displayed first 81 elements.featureBlockImageFirst.forEach((element) => { 82 animateFeatureBlock(element, -50, 0); 83 }); 84 85 // Fades In Page Headers 86 fadeInElements(elements.pageHeaderComponent); 87 88 // Fades In 50/50 Component 89 fadeInElements(elements.fiftyFiftyComponent); 90 91 // Fades In Listing Component 92 fadeInElements(elements.listingComponent); 93 94 // Fades In Hero Component 95 fadeInElements(elements.pageHeroComponent); 96 97 // Fade in PDP template sections 98 fadeInElements(elements.pdpFadeInSection); 99 100 // Fade in PDP product gallery 101 fadeInElements(elements.pdpGalleryFadeInContainer); 102 103 // Fade in Rich Text component 104 fadeInElements(elements.richTextFadeIn); 105 106 // Carousel item fade in 107 ScrollTrigger.batch(":not(.pdp-ajax-carousel-container) .gsap-carousel-item", { 108 batchMax: 3, 109 invalidateOnRefresh: true, 110 onEnter: batch => gsap.to(batch, { opacity: 1, duration: 1, stagger: { each: 0.2 }
110, overwrite: true }) 111 }); 112 113 // Toolbox item fade in 114 fadeInElements(elements.toolboxItem, 75); 115 116 // Find a retailer item fade in 117 //fadeInElements(elements.retailerLocations, 75, '.lsp__location-result-set-wrapper'); 118 119 } else { 120 // Set runAnimations to false to prevent animations 121 runAnimations = false; 122 123 // Clear any existing animations or triggers 124 gsap.globalTimeline.clear(); 125 ScrollTrigger.getAll().forEach(trigger => trigger.kill()); 126 127 // Reset opacity and visibility for elements 128 elementsToSetOpacity.forEach((element) => { 129 if (element) { 130 gsap.set(element, { opacity: 1, visibility: 'visible' }); 131 } 132 }); 133 134 // Reset initial styles for featureBlockTextFirst 135 resetFeatureBlockStyles(elements.featureBlockTextFirst); 136 137 // Reset initial styles for featureBlockImageFirst 138 resetFeatureBlockStyles(elements.featureBlockImageFirst); 139 } 140 } 141 142 function fadeInElements(elements, start = "20% 75%", scroller = null) { 143 elements.forEach((element) => { 144 if (element) { 145 const tl = gsap.timeline({ 146 onComplete: function () { 147 // Removes class to prevent rich text from animating after opening/closing tab component 148 element.classList.remove("gsap-fadein-richtext"); 149 element.classList.remove("gsap-fadein-sku-gallery-container"); 150 }, 151 }); 152 tl.fromTo(element, { autoAlpha: 0 }, { duration: 1, autoAlpha: 1 }); 153 154 ScrollTrigger.create({ 155 trigger: element, 156 animation: tl, 157 toggleActions: 'play none none none', 158 start: start, 159 scroller: scroller 160 }); 161 } 162 }); 163 } 164 165 function animateFeatureBlock(element, xValue, yValue) { 166 const 167 contentBox = element.querySelector('.content-box'), 168 mediaContainer = element.querySelector('.media-container'), 169 buttons = element.querySelectorAll('.reusable-button-set .coh-buttons a'), 170 textButton = element.querySelector('.reusable-button-set .coh-text-button'), 171 tl = gsap.timeline(); 172 173 if (mediaContainer) { 174 tl.fromTo(mediaContainer, { autoAlpha: 0, x: xValue }, { duration: 1, autoAlpha: 1, x: 0 }); 175 } 176 177 if (contentBox) { 178 tl.fromTo(contentBox, { autoAlpha: 0, x: -xValue }, { duration: 1, autoAlpha: 1, x: 0 }, '<.25'); 179 } 180 181 if (buttons) { 182 tl.fromTo(buttons, { autoAlpha: 0, y: 30 }, { duration: 1, autoAlpha: 1, y: 0, stagger: { amount: .25, grid: 'auto' } }, '<.25'); 183 } 184 185 if (textButton) { 186 tl.fromTo(textButton, { autoAlpha: 0, y: 20 }, { duration: 1, autoAlpha: 1, y: 0 }, '<.25'); 187 } 188 189 ScrollTrigger.create({ 190 trigger: element, 191 animation: tl, 192 toggleActions: 'play none none none', 193 start: "20% 75%" 194 }); 195 } 196 197 function resetFeatureBlockStyles(elements) { 198 elements.forEach((element) => { 199 const 200 contentBox = element.querySelector('.content-box'), 201 mediaContainer = element.querySelector('.media-container'), 202 buttons = element.querySelectorAll('.reusable-button-set .coh-buttons a'), 203 textButton = element.querySelector('.reusable-button-set .coh-text-button'); 204 205 if (contentBox && mediaContainer && buttons && textButton) { 206 gsap.set(mediaContainer, { autoAlpha: 1, x: 0 }); 207 gsap.set(contentBox, { autoAlpha: 1, x: 0 }); 208 gsap.set(buttons, { autoAlpha: 1, y: 0 }); 209 gsap.set(textButton, { autoAlpha: 1, y: 0 }); 210 } 211 }); 212 } 213 214 // Function to reset carousel animations 215 function resetCarouselAnimations() { 216 // Clear existing ScrollTriggers for carousel items
217 ScrollTrigger.getAll().forEach(trigger => { 218 if (trigger.trigger.classList.contains('gsap-carousel-item')) { 219 trigger.kill(); 220 } 221 }); 222 223 // Reset GSAP animations for carousel items 224 gsap.set('.gsap-carousel-item', { opacity: 0 }); 225 } 226 } 227 }; 228})(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.