PageSourceSearch

https://foulees.com/shop/js/popup.js

js foulees.com collected 2026-09-26 00:49:13 UTC 24,254 bytes, 554 lines download raw bytes

1// Constantes globales pour les sélecteurs et classes, pour une meilleure maintenabilité.
2const POPUP_CONSTANTS = {
3    OVERLAY_ID: 'globalPopupOverlay',
4    TRIGGER_SELECTOR: '[data-popup-id]',
5    POPUP_SELECTOR: '.popup-moderne',
6    CONTENT_SELECTOR: '.popup-contenu',
7    CLOSE_BUTTON_SELECTOR: '.popup-fermer',
8    ACTIVE_CLASS: 'est-actif',
9    BODY_OPEN_CLASS: 'popup-ouverte',
10    ARIA_HIDDEN_ATTR: 'aria-hidden',
11    DATA_POPUP_URL: 'popupUrl',
12    DATA_POPUP_SOURCE_ID: 'popupSourceId', // pour chargement contenu div cachée dans la page
13    DATA_ORIGINAL_CONTENT: 'originalContent',
14};
15
16const TABS_CONSTANTS = {
17    HIDDEN_CLASS: 'hidden',
18    // Les autres sélecteurs et classes sont passés en paramètres à setupTabs.
19};
20
21// Variables d'état pour le système de popup
22let popupActive = null;
23let dernierElementFocus = null;
24let overlayElement = null; // Stocker l'élément overlay une fois récupéré
25
26// --- Fonctions du Système de Popup ---
27
28/**
29 * Ouvre une popup spécifiée par son ID et charge potentiellement du contenu.
30 * @param {string} popupId - L'ID de la popup à ouvrir.
31 * @param {HTMLElement} declencheur - L'élément HTML qui a déclenché l'ouverture de la popup.
32 */
33async function ouvrirPopup(popupId, declencheur) {
34    if (popupActive && popupActive.id !== popupId) {
35        fermerPopup(false); // Ne pas restaurer le focus immédiatement.
36    }
37
38    const popup = document.getElementById(popupId);
39    if (!popup) {
40        console.error(`Popup avec l'ID "${popupId}" non trouvée.`);
41        return;
42    }
43
44    const contenuPopupDiv = popup.querySelector(POPUP_CONSTANTS.CONTENT_SELECTOR);
45    if (!contenuPopupDiv) {
46        console.error(`L'élément ${POPUP_CONSTANTS.CONTENT_SELECTOR} est introuvable dans la popup ID: ${popupId}`);
47        return;
48    }
49
50    // Sauvegarde le contenu HTML original de la section .popup-contenu si ce n'est pas déjà fait.
51    // Cela est utile si la popup est réutilisée sans URL externe ni source ID,
52    // ou si on veut pouvoir la restaurer à son état initial.
53    if (typeof popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] === 'undefined') {
54        popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] = contenuPopupDiv.innerHTML;
55    }
56
57    dernierElementFocus = document.activeElement;
58    popupActive = popup;
59
60    if (overlayElement) {
61        overlayElement.classList.add(POPUP_CONSTANTS.ACTIVE_CLASS);
62    }
63    popup.classList.add(POPUP_CONSTANTS.ACTIVE_CLASS);
64    popup.removeAttribute(POPUP_CONSTANTS.ARIA_HIDDEN_ATTR);
65    document.body.classList.add(POPUP_CONSTANTS.BODY_OPEN_CLASS);
66
67    const urlContenu = declencheur.dataset[POPUP_CONSTANTS.DATA_POPUP_URL];
68    const sourceIdContenu = declencheur.dataset[POPUP_CONSTANTS.DATA_POPUP_SOURCE_ID];
69
70    if (urlContenu) {
71        contenuPopupDiv.innerHTML = '<p class="popup-loading-message">Chargement du contenu...</p>';
72        try {
73            const response = await fetch(urlContenu);
74            if (!response.ok) {
75                let errorText = response.statusText;
76                try {
77                    const errorData = await response.text();
78                    if (errorData) errorText += ` - ${errorData.substring(0, 100)}`;
79                } catch (e) { /* Ignorer */ }
80                throw new Error(`Erreur HTTP ${response.status}: ${errorText}`);
81            }
82            const htmlContenu = await response.text();
83            contenuPopupDiv.innerHTML = htmlContenu;
84            initTabs(); // Initialiser les onglets DANS le contenu chargé
85
86            // after
87           let after = declencheur.dataset['popupAfter'];
88            if(after != ''){
89                eval(after);
90            }
91
92        } catch (error) {
93            console.error("Erreur lors du chargement du contenu externe de la popup :", error);
94            contenuPopupDiv.innerHTML = `<p class="popup-error-message">Impossible de charger le contenu externe : ${error.message}</p>`;
95        }
96    } else if (sourceIdContenu) {
97        const sourceElement = document.getElementById(sourceIdContenu);
98        if (sourceElement) {
99            contenuPopupDiv.innerHTML = sourceElement.innerHTML;
100            initTabs(); // Initialiser les onglets si le contenu local en contient
101        } else {
102            console.error(`Élément source avec l'ID "${sourceIdContenu}" non trouvé.`);
103            contenuPopupDiv.innerHTML = `<p class="popup-error-message">Impossible de trouver le contenu local (ID: ${sourceIdContenu}).</p>`;
104        }
105    } else {
106        // Pas d'URL externe ni de source ID, utiliser/restaurer le contenu original de la popup.
107        if (typeof popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] !== 'undefined') {
108            contenuPopupDiv.innerHTML = popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT];
109             // Si le contenu original pouvait contenir des onglets qui nécessitent une initialisation.
110            initTabs();
111        } else {
112            contenuPopupDiv.innerHTML = '<p class="popup-no-content-message">Aucun contenu à afficher.</p>';
113        }
114    }
115
116    const boutonFermer = popup.querySelector(POPUP_CONSTANTS.CLOSE_BUTTON_SELECTOR);
117    if (boutonFermer) {
118        boutonFermer.focus();
119    } else {
120        if (!popup.hasAttribute('tabindex')) {
121            popup.setAttribute('tabindex', '-1');
122        }
123        popup.focus();
124    }
125}
126
127/**
128 * Ferme la popup actuellement active.
129 * @param {boolean} [restaurerFocus=true] - Indique si le focus doit être restauré.
130 */
131function fermerPopup(restaurerFocus = true) {
132    if (popupActive) {
133        if (overlayElement) {
134            overlayElement.classList.remove(POPUP_CONSTANTS.ACTIVE_CLASS);
135        }
136        popupActive.classList.remove(POPUP_CONSTANTS.ACTIVE_CLASS);
137        popupActive.setAttribute(POPUP_CONSTANTS.ARIA_HIDDEN_ATTR, 'true');
138        document.body.classList.remove(POPUP_CONSTANTS.BODY_OPEN_CLASS);
139
140        // Optionnel: Vider le contenu de la popup à la fermeture pour s'assurer qu'il est rechargé proprement
141        // ou restauré à son état original la prochaine fois, surtout si `initTabs` est appelé à chaque ouverture.
142        // const contenuPopupDiv = popupActive.querySelector(POPUP_CONSTANTS.CONTENT_SELECTOR);
143        // if (contenuPopupDiv && typeof popupActive.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] !== 'undefined') {
144        //     contenuPopupDiv.innerHTML = popupActive.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT];
145        // } else if (contenuPopupDiv) {
146        //     contenuPopupDiv.innerHTML = ''; // Ou un placeholder si originalContent n'existe pas
147        // }
148
149
150        if (restaurerFocus && dernierElementFocus) {
151            dernierElementFocus.focus();
152        }
153        popupActive = null;
154        dernierElementFocus = null;
155    }
156}
157
158// --- Fonctions du Système d'Onglets ---
159
160/**
161 * Configure la logique pour un ensemble d'onglets.
162 * @param {string} tabContainerSelector - Sélecteur pour le conteneur des boutons d'onglets.
163 * @param {string} buttonSelector - Sélecteur pour les boutons d'onglets.
164 * @param {string} contentSelector - Sélecteur pour les panneaux de contenu d'onglets.
165 * @param {string} activeTabClassName - Nom de la classe CSS pour un bouton d'onglet actif.
166 * @param {string} activeContentClassName - Nom de la classe CSS pour un panneau de contenu actif.
167 * @param {boolean} [isMainTab=false] - Ajuste la recherche du parent de contenu.
168 */
169function setupTabs(tabContainerSelector, buttonSelector, contentSelector, activeTabClassName, activeContentClassName, isMainTab = false) {
170    const tabContainers = document.querySelectorAll(tabContainerSelector);
171
172    tabContainers.forEach(container => {
173        const tabButtons = container.querySelectorAll(buttonSelector);
174        let contentParent = isMainTab ? container.closest('.guidestailles-container') : container.parentElement;
175
176        if (!contentParent) {
177            console.error("Parent pour le contenu des onglets non trouvé pour:", tabContainerSelector);
178            return;
179        }
180        const tabContents = contentParent.querySelectorAll(contentSelector);
181
182        tabButtons.forEach(button => {
183            button.addEventListener('click', () => {
184                tabButtons.forEach(btn => {
185                    btn.classList.remove(activeTabClassName);
186                    btn.setAttribute('aria-selected', 'false');
187                });
188                tabContents.forEach(content => {
189                    content.classList.add(TABS_CONSTANTS.HIDDEN_CLASS);
190                    content.classList.remove(activeContentClassName);
191                    content.setAttribute('aria-hidden', 'true');
192                });
193
194                button.classList.add(activeTabClassName);
195                button.setAttribute('aria-selected', 'true');
196                const targetContentId = button.dataset.tabTarget;
197                const targetSelector = targetContentId.startsWith('#') ? targetContentId : `#${targetContentId}`;
198                const targetContent = contentParent.querySelector(targetSelector);
199
200                if (targetContent) {
201                    targetContent.classList.remove(TABS_CONSTANTS.HIDDEN_CLASS);
202                    targetContent.classList.add(activeContentClassName);
203                    targetContent.setAttribute('aria-hidden', 'false');
204                } else {
205                    // En production, on pourrait vouloir être moins verbeux ou logguer côté serveur si c'est critique.
206                    // console.warn("Contenu cible non trouvé:", targetSelector, "dans:", contentParent);
207                }
208            });
209        });
210        // Optionnel: Activer le premier onglet par défaut si aucun n'est actif et s'il y a des boutons.
211        // if (tabButtons.length > 0 && !container.querySelector(`.${activeTabClassName}`)) {
212        //     tabButtons[0].click();
213        // }
214    });
215}
216
217/**
218 * Initialise toutes les configurations d'onglets définies.
219 * Appelée typiquement après un fetch dans une popup pour activer les onglets du nouveau contenu.
220 */
221function initTabs() {
222    setupTabs('.tabs-main', '.tab-main-button', '.tab-main-content', 'active-tab', 'active-content', true);
223    setupTabs('#textile .tabs-textile', '.tab-secondary-button', '.tab-secondary-content', 'active-tab-secondary', 'active-content-secondary');
224    setupTabs('#velos .tabs-velos', '.tab-secondary-button', '.tab-secondary-content', 'active-tab-secondary', 'active-content-secondary');
225    // Ajouter d'autres appels à setupTabs pour d'autres systèmes d'onglets si nécessaire.
226}
227
228
229// --- Fonctions d'Initialisation Principales ---
230
231/**
232 * Initialise le système de gestion des popups.
233 * Attache les écouteurs d'événements nécessaires.
234 */
235function initializePopupSystem() {
236    overlayElement = document.getElementById(POPUP_CONSTANTS.OVERLAY_ID);
237    const declencheursPopup = document.querySelectorAll(POPUP_CONSTANTS.TRIGGER_SELECTOR);
238    const toutesPopups = document.querySelectorAll(POPUP_CONSTANTS.POPUP_SELECTOR);
239
240    if (!overlayElement) {
241        // En production, un avertissement dans la console peut toujours être utile pour les développeurs.
242        console.warn(`L'élément overlay avec l'ID '${POPUP_CONSTANTS.OVERLAY_ID}' est manquant. Certaines fonctionnalités pourraient être affectées.`);
243    }
244
245    declencheursPopup.forEach(bouton => {
246        const popupId = bouton.dataset.popupId;
247        if (popupId) {
248            bouton.addEventListener('click', (event) => {
249                event.preventDefault();
250                ouvrirPopup(popupId, bouton);
251            });
252        } else {
253            // console.warn("Un déclencheur n'a pas 'data-popup-id'.", bouton);
254        }
255    });
256
257    toutesPopups.forEach(popup => {
258        const boutonFermer = popup.querySelector(POPUP_CONSTANTS.CLOSE_BUTTON_SELECTOR);
259        if (boutonFermer) {
260            boutonFermer.addEventListener('click', () => fermerPopup());
261        }
262    });
263
264    if (overlayElement) {
265        overlayElement.addEventListener('click', () => fermerPopup());
266    }
267
268    document.addEventListener('keydown', (event) => {
269        if (event.key === 'Escape' && popupActive) {
270            fermerPopup();
271        }
272    });
273}
274
275/**
276 * Initialise les onglets statiques présents sur la page au chargement initial.
277 */
278function initializeStaticTabs() {
279    // Si des onglets statiques doivent être initialisés au chargement de la page,
280    // leur initialisation se ferait ici.
281    // Actuellement, initTabs() est appelé uniquement depuis ouvrirPopup() pour le contenu dynamique.
282}
283
284
285// --- Point d'Entrée Principal ---
286// Attend que le DOM soit entièrement chargé avant d'exécuter les initialisations.
287document.addEventListener('DOMContentLoaded', () => {
288    initializePopupSystem();
289    initializeStaticTabs();
290});
291
292
293
294
295
296
297
298
299// // Constantes globales pour les sélecteurs et classes, pour une meilleure maintenabilité.
300// const POPUP_CONSTANTS = {
301//     OVERLAY_ID: 'globalPopupOverlay',
302//     TRIGGER_SELECTOR: '[data-popup-id]',
303//     POPUP_SELECTOR: '.popup-moderne',
304//     CONTENT_SELECTOR: '.popup-contenu',
305//     CLOSE_BUTTON_SELECTOR: '.popup-fermer',
306//     ACTIVE_CLASS: 'est-actif',
307//     BODY_OPEN_CLASS: 'popup-ouverte',
308//     ARIA_HIDDEN_ATTR: 'aria-hidden',
309//     DATA_POPUP_URL: 'popupUrl',
310//     DATA_ORIGINAL_CONTENT: 'originalContent',
311// };
312
313// const TABS_CONSTANTS = {
314//     HIDDEN_CLASS: 'hidden',
315//     // Les autres sélecteurs et classes sont passés en paramètres à setupTabs.
316// };
317
318// // Variables d'état pour le système de popup
319// let popupActive = null;
320// let dernierElementFocus = null;
321// let overlayElement = null; // Stocker l'élément overlay une fois récupéré
322
323// // --- Fonctions du Système de Popup ---
324
325// /**
326//  * Ouvre une popup spécifiée par son ID et charge potentiellement du contenu externe.
327//  * @param {string} popupId - L'ID de la popup à ouvrir.
328//  * @param {HTMLElement} declencheur - L'élément HTML qui a déclenché l'ouverture de la popup.
329//  */
330// async function ouvrirPopup(popupId, declencheur) {
331//     if (popupActive && popupActive.id !== popupId) {
332//         fermerPopup(false); // Ne pas restaurer le focus immédiatement.
333//     }
334
335//     const popup = document.getElementById(popupId);
336//     if (!popup) {
337//         console.error(`Popup avec l'ID "${popupId}" non trouvée.`);
338//         return;
339//     }
340
341//     const contenuPopupDiv = popup.querySelector(POPUP_CONSTANTS.CONTENT_SELECTOR);
342//     if (!contenuPopupDiv) {
343//         console.error(`L'élément ${POPUP_CONSTANTS.CONTENT_SELECTOR} est introuvable dans la popup ID: ${popupId}`);
344//         return;
345//     }
346
347//     if (typeof popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] === 'undefined') {
348//         popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] = contenuPopupDiv.innerHTML;
349//     }
350
351//     dernierElementFocus = document.activeElement;
352//     popupActive = popup;
353
354//     if (overlayElement) {
355//         overlayElement.classList.add(POPUP_CONSTANTS.ACTIVE_CLASS);
356//     }
357//     popup.classList.add(POPUP_CONSTANTS.ACTIVE_CLASS);
358//     popup.removeAttribute(POPUP_CONSTANTS.ARIA_HIDDEN_ATTR);
359//     document.body.classList.add(POPUP_CONSTANTS.BODY_OPEN_CLASS);
360
361//     const urlContenu = declencheur.dataset[POPUP_CONSTANTS.DATA_POPUP_URL];
362
363//     if (urlContenu) {
364//         contenuPopupDiv.innerHTML = '<p class="popup-loading-message">Chargement du contenu...</p>'; // Utiliser une classe pour le style
365//         try {
366//             const response = await fetch(urlContenu);
367//             if (!response.ok) {
368//                 let errorText = response.statusText;
369//                 try {
370//                     const errorData = await response.text();
371//                     if (errorData) errorText += ` - ${errorData.substring(0, 100)}`;
372//                 } catch (e) { /* Ignorer */ }
373//                 throw new Error(`Erreur HTTP ${response.status}: ${errorText}`);
374//             }
375//             const htmlContenu = await response.text();
376//             contenuPopupDiv.innerHTML = htmlContenu;
377//             initTabs(); // Initialiser les onglets DANS le contenu chargé
378//         } catch (error) {
379//             console.error("Erreur lors du chargement du contenu de la popup :", error);
380//             contenuPopupDiv.innerHTML = `<p class="popup-error-message">Impossible de charger le contenu : ${error.message}</p>`; // Classe pour style
381//         }
382//     } else {
383//         if (typeof popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT] !== 'undefined') {
384//             contenuPopupDiv.innerHTML = popup.dataset[POPUP_CONSTANTS.DATA_ORIGINAL_CONTENT];
385//         } else {
386//             contenuPopupDiv.innerHTML = '<p class="popup-no-content-message">Aucun contenu à afficher.</p>'; // Classe pour style
387//         }
388//     }
389
390//     const boutonFermer = popup.querySelector(POPUP_CONSTANTS.CLOSE_BUTTON_SELECTOR);
391//     if (boutonFermer) {
392//         boutonFermer.focus();
393//     } else {
394//         if (!popup.hasAttribute('tabindex')) {
395//             popup.setAttribute('tabindex', '-1');
396//         }
397//         popup.focus();
398//     }
399// }
400
401// /**
402//  * Ferme la popup actuellement active.
403//  * @param {boolean} [restaurerFocus=true] - Indique si le focus doit être restauré.
404//  */
405// function fermerPopup(restaurerFocus = true) {
406//     if (popupActive) {
407//         if (overlayElement) {
408//             overlayElement.classList.remove(POPUP_CONSTANTS.ACTIVE_CLASS);
409//         }
410//         popupActive.classList.remove(POPUP_CONSTANTS.ACTIVE_CLASS);
411//         popupActive.setAttribute(POPUP_CONSTANTS.ARIA_HIDDEN_ATTR, 'true');
412//         document.body.classList.remove(POPUP_CONSTANTS.BODY_OPEN_CLASS);
413
414//         if (restaurerFocus && dernierElementFocus) {
415//             dernierElementFocus.focus();
416//         }
417//         popupActive = null;
418//         dernierElementFocus = null;
419//     }
420// }
421
422// // --- Fonctions du Système d'Onglets ---
423
424// /**
425//  * Configure la logique pour un ensemble d'onglets.
426//  * @param {string} tabContainerSelector - Sélecteur pour le conteneur des boutons d'onglets.
427//  * @param {string} buttonSelector - Sélecteur pour les boutons d'onglets.
428//  * @param {string} contentSelector - Sélecteur pour les panneaux de contenu d'onglets.
429//  * @param {string} activeTabClassName - Nom de la classe CSS pour un bouton d'onglet actif.
430//  * @param {string} activeContentClassName - Nom de la classe CSS pour un panneau de contenu actif.
431//  * @param {boolean} [isMainTab=false] - Ajuste la recherche du parent de contenu.
432//  */
433// function setupTabs(tabContainerSelector, buttonSelector, contentSelector, activeTabClassName, activeContentClassName, isMainTab = false) {
434//     const tabContainers = document.querySelectorAll(tabContainerSelector);
435
436//     tabContainers.forEach(container => {
437//         const tabButtons = container.querySelectorAll(buttonSelector);
438//         let contentParent = isMainTab ? container.closest('.guidestailles-container') : container.parentElement;
439
440//         if (!contentParent) {
441//             console.error("Parent pour le contenu des onglets non trouvé pour:", tabContainerSelector);
442//             return;
443//         }
444//         const tabContents = contentParent.querySelectorAll(contentSelector);
445
446//         tabButtons.forEach(button => {
447//             button.addEventListener('click', () => {
448//                 tabButtons.forEach(btn => {
449//                     btn.classList.remove(activeTabClassName);
450//                     btn.setAttribute('aria-selected', 'false');
451//                 });
452//                 tabContents.forEach(content => {
453//                     content.classList.add(TABS_CONSTANTS.HIDDEN_CLASS);
454//                     content.classList.remove(activeContentClassName);
455//                     content.setAttribute('aria-hidden', 'true');
456//                 });
457
458//                 button.classList.add(activeTabClassName);
459//                 button.setAttribute('aria-selected', 'true');
460//                 const targetContentId = button.dataset.tabTarget;
461//                 const targetSelector = targetContentId.startsWith('#') ? targetContentId : `#${targetContentId}`;
462//                 const targetContent = contentParent.querySelector(targetSelector);
463
464//                 if (targetContent) {
465//                     targetContent.classList.remove(TABS_CONSTANTS.HIDDEN_CLASS);
466//                     targetContent.classList.add(activeContentClassName);
467//                     targetContent.setAttribute('aria-hidden', 'false');
468//                 } else {
469//                     // En production, on pourrait vouloir être moins verbeux ou logguer côté serveur si c'est critique.
470//                     // console.warn("Contenu cible non trouvé:", targetSelector, "dans:", contentParent);
471//                 }
472//             });
473//         });
474//         // Optionnel: Activer le premier onglet par défaut si aucun n'est actif et s'il y a des boutons.
475//         // if (tabButtons.length > 0 && !container.querySelector(`.${activeTabClassName}`)) {
476//         //     tabButtons[0].click();
477//         // }
478//     });
479// }
480
481// /**
482//  * Initialise toutes les configurations d'onglets définies.
483//  * Appelée typiquement après un fetch dans une popup pour activer les onglets du nouveau contenu.
484//  */
485// function initTabs() {
486//     setupTabs('.tabs-main', '.tab-main-button', '.tab-main-content', 'active-tab', 'active-content', true);
487//     setupTabs('#textile .tabs-textile', '.tab-secondary-button', '.tab-secondary-content', 'active-tab-secondary', 'active-content-secondary');
488//     setupTabs('#velos .tabs-velos', '.tab-secondary-button', '.tab-secondary-content', 'active-tab-secondary', 'active-content-secondary');
489//     // Ajouter d'autres appels à setupTabs pour d'autres systèmes d'onglets si nécessaire.
490// }
491
492
493// // --- Fonctions d'Initialisation Principales ---
494
495// /**
496//  * Initialise le système de gestion des popups.
497//  * Attache les écouteurs d'événements nécessaires.
498//  */
499// function initializePopupSystem() {
500//     overlayElement = document.getElementById(POPUP_CONSTANTS.OVERLAY_ID);
501//     const declencheursPopup = document.querySelectorAll(POPUP_CONSTANTS.TRIGGER_SELECTOR);
502//     const toutesPopups = document.querySelectorAll(POPUP_CONSTANTS.POPUP_SELECTOR);
503
504//     if (!overlayElement) {
505//         // En production, un avertissement dans la console peut toujours être utile pour les développeurs.
506//         console.warn(`L'élément overlay avec l'ID '${POPUP_CONSTANTS.OVERLAY_ID}' est manquant. Certaines fonctionnalités pourraient être affectées.`);
507//     }
508
509//     declencheursPopup.forEach(bouton => {
510//         const popupId = bouton.dataset.popupId;
511//         if (popupId) {
512//             bouton.addEventListener('click', (event) => {
513//                 event.preventDefault();
514//                 ouvrirPopup(popupId, bouton);
515//             });
516//         } else {
517//             // console.warn("Un déclencheur n'a pas 'data-popup-id'.", bouton);
518//         }
519//     });
520
521//     toutesPopups.forEach(popup => {
522//         const boutonFermer = popup.querySelector(POPUP_CONSTANTS.CLOSE_BUTTON_SELECTOR);
523//         if (boutonFermer) {
524//             boutonFermer.addEventListener('click', () => fermerPopup());
525//         }
526//     });
527
528//     if (overlayElement) {
529//         overlayElement.addEventListener('click', () => fermerPopup());
530//     }
531
532//     document.addEventListener('keydown', (event) => {
533//         if (event.key === 'Escape' && popupActive) {
534//             fermerPopup();
535//         }
536//     });
537// }
538
539// /**
540//  * Initialise les onglets statiques présents sur la page au chargement initial.
541//  */
542// function initializeStaticTabs() {
543//     // Si des onglets statiques doivent être initialisés au chargement de la page,
544//     // leur initialisation se ferait ici.
545//     // Actuellement, initTabs() est appelé uniquement depuis ouvrirPopup() pour le contenu dynamique.
546// }
547
548
549// // --- Point d'Entrée Principal ---
550// // Attend que le DOM soit entièrement chargé avant d'exécuter les initialisations.
551// document.addEventListener('DOMContentLoaded', () => {
552//     initializePopupSystem();
553//     initializeStaticTabs();
554// });

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.