PageSourceSearch

https://montagut.com/themes/child_classic_montagut/assets/js/sticky-add-to-cart.js

js montagut.com collected 2026-10-08 01:33:00 UTC 5,848 bytes, 200 lines download raw bytes

1/**
2 * Sticky Add to Cart - Mobile Only
3 * Affiche un bouton fixé en bas quand le bouton original a été dépassé (scroll vers le bas)
4 * Compatible avec les changements de variantes PrestaShop (AJAX reload)
5 */
6
7(function() {
8    'use strict';
9
10    // Configuration
11    const CONFIG = {
12        mobileBreakpoint: 991,
13        throttleDelay: 100,
14        scrollOffset: 100 // Marge en pixels au-dessus du bouton original
15    };
16
17    // Éléments DOM (réinitialisés après chaque update)
18    let originalButton = null;
19    let stickyContainer = null;
20    let stickyButton = null;
21
22    /**
23     * Vérifie si on est sur mobile
24     */
25    function isMobile() {
26        return window.innerWidth <= CONFIG.mobileBreakpoint;
27    }
28
29    /**
30     * Throttle function pour optimiser les performances
31     */
32    function throttle(func, limit) {
33        let inThrottle;
34        return function(...args) {
35            if (!inThrottle) {
36                func.apply(this, args);
37                inThrottle = true;
38                setTimeout(() => inThrottle = false, limit);
39            }
40        };
41    }
42
43    /**
44     * Vérifie si le bouton original a été dépassé (scrollé en dessous)
45     * Retourne true si le bas du bouton est AU-DESSUS du viewport
46     */
47    function hasScrolledPastButton(el) {
48        if (!el) return false;
49        
50        const rect = el.getBoundingClientRect();
51        return rect.bottom < 0;
52    }
53
54    /**
55     * Scroll vers le bouton original
56     */
57    function scrollToOriginalButton() {
58        if (!originalButton) return;
59        
60        const rect = originalButton.getBoundingClientRect();
61        const absoluteTop = rect.top + window.pageYOffset;
62        
63        window.scrollTo({
64            top: absoluteTop - CONFIG.scrollOffset,
65            behavior: 'smooth'
66        });
67    }
68
69    /**
70     * Rafraîchit les références DOM (appelé après chaque update produit)
71     */
72    function refreshDOMReferences() {
73        originalButton = document.querySelector('#js-original-add-to-cart');
74        stickyContainer = document.querySelector('#js-sticky-add-to-cart');
75        stickyButton = document.querySelector('#js-sticky-add-to-cart-btn');
76        
77        // Réattacher le click handler sur le nouveau bouton sticky
78        if (stickyButton) {
79            stickyButton.removeEventListener('click', handleStickyClick);
80            stickyButton.addEventListener('click', handleStickyClick);
81        }
82        
83        // Mettre à jour l'état disabled
84        updateStickyButtonState();
85        
86        // Mettre à jour la visibilité
87        updateStickyVisibility();
88    }
89
90    /**
91     * Met à jour la visibilité du sticky
92     */
93    function updateStickyVisibility() {
94        if (!isMobile()) {
95            hideStickyButton();
96            return;
97        }
98
99        // Rafraîchir les références si elles sont nulles
100        if (!originalButton || !stickyContainer) {
101            refreshDOMReferences();
102        }
103
104        if (!originalButton || !stickyContainer) {
105            return;
106        }
107
108        const hasScrolledPast = hasScrolledPastButton(originalButton);
109
110        if (hasScrolledPast) {
111            showStickyButton();
112        } else {
113            hideStickyButton();
114        }
115    }
116
117    /**
118     * Affiche le bouton sticky
119     */
120    function showStickyButton() {
121        if (stickyContainer && !stickyContainer.classList.contains('is-visible')) {
122            stickyContainer.classList.add('is-visible');
123            document.body.classList.add('sticky-cart-active');
124        }
125    }
126
127    /**
128     * Cache le bouton sticky
129     */
130    function hideStickyButton() {
131        if (stickyContainer && stickyContainer.classList.contains('is-visible')) {
132            stickyContainer.classList.remove('is-visible');
133            document.body.classList.remove('sticky-cart-active');
134        }
135    }
136
137    /**
138     * Gère le clic sur le bouton sticky
139     */
140    function handleStickyClick(e) {
141        e.preventDefault();
142        
143        // Scroll vers le bouton original
144        scrollToOriginalButton();
145        
146        // Trouve le vrai bouton add-to-cart dans le formulaire
147        const realButton = document.querySelector('#js-original-add-to-cart .add-to-cart');
148        
149        if (realButton && !realButton.disabled) {
150            // Petit délai pour laisser le scroll se faire
151            setTimeout(function() {
152                realButton.click();
153            }, 300);
154        }
155    }
156
157    /**
158     * Met à jour l'état disabled du bouton sticky
159     */
160    function updateStickyButtonState() {
161        const realButton = document.querySelector('#js-original-add-to-cart .add-to-cart');
162        
163        if (realButton && stickyButton) {
164            stickyButton.disabled = realButton.disabled;
165        }
166    }
167
168    /**
169     * Initialisation
170     */
171    function init() {
172        // Rafraîchir les références DOM
173        refreshDOMReferences();
174
175        // Event listeners globaux (une seule fois)
176        window.addEventListener('scroll', throttle(updateStickyVisibility, CONFIG.throttleDelay), { passive: true });
177        window.addEventListener('resize', throttle(updateStickyVisibility, CONFIG.throttleDelay), { passive: true });
178
179        // Écouter les événements PrestaShop de mise à jour produit (changement variante)
180        if (typeof prestashop !== 'undefined') {
181            prestashop.on('updatedProduct', function() {
182                // Attendre que le DOM soit mis à jour
183                setTimeout(function() {
184                    refreshDOMReferences();
185                }, 150);
186            });
187        }
188
189        // Check initial
190        updateStickyVisibility();
191    }
192
193    // Lancement
194    if (document.readyState === 'loading') {
195        document.addEventListener('DOMContentLoaded', init);
196    } else {
197        init();
198    }
199
200})();

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.