PageSourceSearch

https://www.sif-artois.com/wp-content/plugins/orion-blocks/acf-blocks/tabbed-content/script.js?ver=1783328769

js sif-artois.com collected 2026-09-29 02:43:19 UTC 8,631 bytes, 249 lines download raw bytes

1/**
2 * Script JavaScript pour le bloc ACF Tabbed Content
3 * Gère le changement d'onglets avec transitions et navigation au clavier
4 */
5
6(function () {
7    'use strict';
8
9    /**
10     * Initialiser un bloc de contenu à onglets spécifique
11     */
12    function initTabbedContent(blockElement) {
13        const panels = blockElement.querySelectorAll('.tabbed-content__panel');
14
15        if (panels.length === 0) {
16            console.warn('Aucun panneau trouvé dans le bloc');
17            return;
18        }
19
20        // Nombre total d'onglets (basé sur les panneaux)
21        const totalTabs = panels.length;
22
23        /**
24         * Activer un onglet spécifique
25         */
26        function activateTab(targetIndex) {
27            // Record if focus was inside the block to restore it correctly
28            const currentFocus = document.activeElement;
29            const focusWasOnTab = currentFocus && currentFocus.classList.contains('tabbed-content__tab');
30
31            // Mettre à jour tous les panneaux
32            panels.forEach(function (panel, panelIndex) {
33                const isTargetPanel = panelIndex === targetIndex;
34
35                // Hard switching - instant change without transitions
36                if (isTargetPanel) {
37                    panel.classList.add('is-active');
38                    panel.removeAttribute('hidden');
39                    panel.setAttribute('aria-hidden', 'false');
40                } else {
41                    panel.classList.remove('is-active');
42                    panel.setAttribute('aria-hidden', 'true');
43                }
44
45                // Mettre à jour tous les boutons d'onglet dans ce panneau
46                const tabButtons = panel.querySelectorAll('.tabbed-content__tab');
47                tabButtons.forEach(function (tab, tabIndex) {
48                    const isActiveTab = tabIndex === targetIndex;
49
50                    tab.classList.toggle('is-active', isActiveTab);
51                    tab.setAttribute('aria-selected', isActiveTab ? 'true' : 'false');
52                    // On ne modifie plus tabindex ici pour permettre le tab focus sur tous les onglets
53                });
54            });
55
56            // Si le focus était sur un onglet, le déplacer vers le même onglet dans le nouveau panneau actif
57            if (focusWasOnTab) {
58                const newActivePanel = blockElement.querySelector('.tabbed-content__panel.is-active');
59                if (newActivePanel) {
60                    const newTabButton = newActivePanel.querySelector('.tabbed-content__tab[data-tab-index="' + targetIndex + '"]');
61                    if (newTabButton) {
62                        newTabButton.focus();
63                    }
64                }
65            }
66
67            // Événement personnalisé
68            const event = new CustomEvent('tabbed-content-changed', {
69                detail: {
70                    block: blockElement,
71                    activeIndex: targetIndex
72                }
73            });
74            blockElement.dispatchEvent(event);
75        }
76
77        /**
78         * Gérer les clics sur les onglets
79         */
80        panels.forEach(function (panel) {
81            const tabButtons = panel.querySelectorAll('.tabbed-content__tab');
82
83            tabButtons.forEach(function (tab) {
84                // Éviter d'ajouter plusieurs event listeners
85                if (tab.dataset.initialized) {
86                    return;
87                }
88                tab.dataset.initialized = 'true';
89
90                tab.addEventListener('click', function (e) {
91                    e.preventDefault();
92                    const targetIndex = parseInt(tab.dataset.tabIndex, 10);
93                    activateTab(targetIndex);
94                });
95
96                /**
97                 * Gérer la navigation au clavier
98                 */
99                tab.addEventListener('keydown', function (e) {
100                    const currentIndex = parseInt(tab.dataset.tabIndex, 10);
101                    let newIndex = -1;
102
103                    switch (e.key) {
104                        case 'ArrowLeft':
105                        case 'ArrowUp':
106                            e.preventDefault();
107                            newIndex = currentIndex > 0 ? currentIndex - 1 : totalTabs - 1;
108                            break;
109
110                        case 'ArrowRight':
111                        case 'ArrowDown':
112                            e.preventDefault();
113                            newIndex = currentIndex < totalTabs - 1 ? currentIndex + 1 : 0;
114                            break;
115
116                        case 'Home':
117                            e.preventDefault();
118                            newIndex = 0;
119                            break;
120
121                        case 'End':
122                            e.preventDefault();
123                            newIndex = totalTabs - 1;
124                            break;
125
126                        case 'Enter':
127                        case ' ':
128                            e.preventDefault();
129                            activateTab(currentIndex);
130                            return;
131                    }
132
133                    if (newIndex !== -1) {
134                        activateTab(newIndex);
135                        // Focus is handled inside activateTab now
136                    }
137                });
138            });
139        });
140
141        // Marquer le bloc comme initialisé
142        blockElement.classList.add('is-initialized');
143
144        // Événement personnalisé d'initialisation
145        const initEvent = new CustomEvent('tabbed-content-initialized', {
146            detail: {
147                block: blockElement,
148                tabCount: totalTabs
149            }
150        });
151        blockElement.dispatchEvent(initEvent);
152    }
153
154    /**
155     * Initialiser tous les blocs de contenu à onglets de la page
156     */
157    function initAllTabbedContent() {
158        const blocks = document.querySelectorAll('.tabbed-content:not(.is-initialized)');
159
160        if (blocks.length === 0) {
161            return;
162        }
163
164        blocks.forEach(function (block) {
165            initTabbedContent(block);
166        });
167    }
168
169    /**
170     * Initialiser au chargement du DOM
171     */
172    if (document.readyState === 'loading') {
173        document.addEventListener('DOMContentLoaded', initAllTabbedContent);
174    } else {
175        initAllTabbedContent();
176    }
177
178    /**
179     * Ré-initialiser après le chargement complet de la page
180     */
181    window.addEventListener('load', function () {
182        setTimeout(initAllTabbedContent, 100);
183    });
184
185    /**
186     * MutationObserver — éditeur Gutenberg / ACF preview
187     * ACF injecte le HTML du bloc après le DOMContentLoaded,
188     * l'observer détecte chaque nouveau rendu et réinitialise.
189     */
190    if (typeof MutationObserver !== 'undefined' && document.body) {
191        var editorObserver = new MutationObserver(function (mutations) {
192            var needsInit = false;
193            mutations.forEach(function (mutation) {
194                mutation.addedNodes.forEach(function (node) {
195                    if (node.nodeType !== 1) return;
196                    if (
197                        (node.classList && node.classList.contains('tabbed-content')) ||
198                        (node.querySelector && node.querySelector('.tabbed-content'))
199                    ) {
200                        needsInit = true;
201                    }
202                });
203            });
204            if (needsInit) {
205                initAllTabbedContent();
206            }
207        });
208
209        editorObserver.observe(document.body, { childList: true, subtree: true });
210    }
211
212    /**
213     * API publique pour initialiser manuellement un bloc
214     */
215    window['orion-blocksInitTabbedContent'] = function (element) {
216        if (!element) {
217            console.error('Élément tabbed content non fourni');
218            return;
219        }
220
221        // Retirer la classe d'initialisation si présente
222        element.classList.remove('is-initialized');
223
224        // Initialiser
225        initTabbedContent(element);
226    };
227
228    /**
229     * API publique pour activer un onglet spécifique
230     */
231    window['orion-blocksActivateTab'] = function (blockElement, tabIndex) {
232        if (!blockElement) {
233            console.error('Élément tabbed content non fourni');
234            return;
235        }
236
237        const tabs = blockElement.querySelectorAll('.tabbed-content__tab');
238
239        if (tabIndex < 0 || tabIndex >= tabs.length) {
240            console.error('Index d\'onglet invalide:', tabIndex);
241            return;
242        }
243
244        // Simuler un clic sur l'onglet
245        tabs[tabIndex].click();
246    };
247
248})();
249

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.