PageSourceSearch

https://mug.org.ar/wp-content/plugins/dilux-one-magic-tabs/assets/js/tabs.js?ver=1.0.1

js mug.org.ar collected 2026-10-02 11:48:04 UTC 13,759 bytes, 383 lines download raw bytes

1/**
2 * Dilux One Tabs - Frontend JavaScript
3 */
4
5class DiluxMagicTabs {
6    constructor(element) {
7        this.element = element;
8        this.groupId = element.dataset.groupId;
9        this.componentType = element.dataset.componentType || 'tabs';
10        this.orientation = element.dataset.orientation || 'horizontal';
11        this.animation = element.dataset.animation || 'fade';
12        this.lazyLoading = element.dataset.lazyLoading === 'true';
13        this.deepLinking = element.dataset.deepLinking === 'true';
14        this.mobileBreakpoint = 768;
15
16        // Check if this is an accordion component
17        this.isAccordion = this.componentType === 'accordion';
18
19        if (this.isAccordion) {
20            // Accordion elements
21            this.accordionBehavior = element.dataset.accordionBehavior || 'single';
22            this.accordionItems = element.querySelectorAll('.dilux-accordion-item');
23            this.accordionHeaders = element.querySelectorAll('.dilux-accordion-header');
24            this.accordionPanels = element.querySelectorAll('.dilux-accordion-panel');
25            this.loadedTabs = new Set(); // Track loaded content
26
27            // Find initially open panels
28            this.accordionPanels.forEach((panel, index) => {
29                if (panel.classList.contains('active')) {
30                    this.loadedTabs.add(index);
31                }
32            });
33        } else {
34            // Regular tabs elements
35            this.tabButtons = element.querySelectorAll('.dilux-tab-button');
36            this.tabPanels = element.querySelectorAll('.dilux-tab-panel');
37            this.activeIndex = 0;
38            this.loadedTabs = new Set([0]); // First tab is already loaded
39        }
40
41        this.init();
42    }
43
44    init() {
45        if (this.isAccordion) {
46            // Initialize accordion
47            this.initAccordion();
48        } else {
49            // Initialize regular tabs
50            this.initRegularTabs();
51        }
52
53        // Handle deep linking
54        if (this.deepLinking) {
55            this.handleDeepLinking();
56            window.addEventListener('hashchange', () => this.handleDeepLinking());
57        }
58    }
59
60    initRegularTabs() {
61        // Attach click handlers to tab buttons
62        this.tabButtons.forEach((button, index) => {
63            button.addEventListener('click', () => {
64                this.switchTab(index);
65            });
66        });
67
68        // Transform to accordion on mobile
69        if (window.innerWidth <= this.mobileBreakpoint) {
70            this.transformToAccordion();
71        }
72
73        // Re-check on resize (with debounce)
74        let resizeTimer;
75        window.addEventListener('resize', () => {
76            clearTimeout(resizeTimer);
77            resizeTimer = setTimeout(() => {
78                if (window.innerWidth <= this.mobileBreakpoint && !this.element.classList.contains('dilux-magic-tabs-accordion')) {
79                    this.transformToAccordion();
80                } else if (window.innerWidth > this.mobileBreakpoint && this.element.classList.contains('dilux-magic-tabs-accordion')) {
81                    this.restoreFromAccordion();
82                }
83            }, 250);
84        });
85    }
86
87    initAccordion() {
88        // Attach click handlers to accordion headers
89        this.accordionHeaders.forEach((header, index) => {
90            header.addEventListener('click', () => {
91                this.toggleAccordionItem(index);
92            });
93        });
94    }
95
96    toggleAccordionItem(index) {
97        const item = this.accordionItems[index];
98        const header = this.accordionHeaders[index];
99        const panel = this.accordionPanels[index];
100        const isActive = item.classList.contains('active');
101
102        if (isActive) {
103            // Close this item
104            item.classList.remove('active');
105            header.setAttribute('aria-expanded', 'false');
106            panel.classList.remove('active');
107        } else {
108            // If behavior is 'single', close all other items first
109            if (this.accordionBehavior === 'single') {
110                this.accordionItems.forEach((otherItem, i) => {
111                    if (i !== index) {
112                        otherItem.classList.remove('active');
113                        this.accordionHeaders[i].setAttribute('aria-expanded', 'false');
114                        this.accordionPanels[i].classList.remove('active');
115                    }
116                });
117            }
118
119            // Open this item
120            item.classList.add('active');
121            header.setAttribute('aria-expanded', 'true');
122            panel.classList.add('active');
123
124            // Load content if lazy loading
125            if (this.lazyLoading && !this.loadedTabs.has(index)) {
126                this.loadAccordionContent(panel, index);
127            }
128
129            // Update URL hash if deep linking enabled
130            if (this.deepLinking) {
131                const itemElement = this.accordionItems[index];
132                const slug = itemElement.dataset.tabSlug;
133                if (slug) {
134                    history.pushState(null, null, '#tab-' + slug);
135                }
136            }
137        }
138    }
139
140    loadAccordionContent(panel, index) {
141        const itemElement = this.accordionItems[index];
142        const tabId = itemElement.dataset.tabId;
143
144        if (!tabId || !panel.dataset.lazy) {
145            return;
146        }
147
148        const contentWrapper = panel.querySelector('.dilux-accordion-content');
149
150        // Show loading state
151        contentWrapper.innerHTML = '<div class="dilux-accordion-loading"><p>Loading...</p></div>';
152
153        // AJAX request
154        fetch(diluxMagicTabsData.ajaxUrl, {
155            method: 'POST',
156            headers: {
157                'Content-Type': 'application/x-www-form-urlencoded',
158            },
159            body: new URLSearchParams({
160                action: 'dilux_magic_tabs_load_content',
161                nonce: diluxMagicTabsData.nonce,
162                tab_id: tabId,
163            }),
164        })
165        .then(response => response.json())
166        .then(data => {
167            if (data.success) {
168                contentWrapper.innerHTML = data.data.content;
169                panel.removeAttribute('data-lazy');
170                this.loadedTabs.add(index);
171            } else {
172                contentWrapper.innerHTML = '<div class="dilux-accordion-error"><p>Error loading content.</p></div>';
173            }
174        })
175        .catch(error => {
176            contentWrapper.innerHTML = '<div class="dilux-accordion-error"><p>Error loading content.</p></div>';
177        });
178    }
179
180    switchTab(index) {
181        if (index === this.activeIndex) {
182            return; // Already active
183        }
184
185        const fromPanel = this.tabPanels[this.activeIndex];
186        const toPanel = this.tabPanels[index];
187        const toButton = this.tabButtons[index];
188
189        // Deactivate current tab
190        this.tabButtons[this.activeIndex].classList.remove('active');
191        this.tabButtons[this.activeIndex].setAttribute('aria-selected', 'false');
192        fromPanel.classList.remove('active');
193
194        // Update active index
195        this.activeIndex = index;
196
197        // Lazy load if needed
198        if (this.lazyLoading && !this.loadedTabs.has(index)) {
199            this.loadTabContent(toPanel, () => {
200                this.activateTab(toButton, toPanel);
201            });
202        } else {
203            this.activateTab(toButton, toPanel);
204        }
205
206        // Update URL hash if deep linking enabled
207        if (this.deepLinking) {
208            const slug = toButton.dataset.tabSlug;
209            if (slug) {
210                history.pushState(null, null, '#tab-' + slug);
211            }
212        }
213    }
214
215    activateTab(button, panel) {
216        button.classList.add('active');
217        button.setAttribute('aria-selected', 'true');
218        panel.classList.add('active');
219
220        // Scroll to tabs container (smooth scroll)
221        if (window.innerWidth <= this.mobileBreakpoint) {
222            this.element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
223        }
224    }
225
226    loadTabContent(panel, callback) {
227        const tabId = panel.dataset.tabId;
228
229        if (!tabId || !panel.dataset.lazy) {
230            callback();
231            return;
232        }
233
234        // Show loading state
235        panel.innerHTML = '<div class="dilux-tab-loading"><p>Loading...</p></div>';
236
237        // AJAX request
238        fetch(diluxMagicTabsData.ajaxUrl, {
239            method: 'POST',
240            headers: {
241                'Content-Type': 'application/x-www-form-urlencoded',
242            },
243            body: new URLSearchParams({
244                action: 'dilux_magic_tabs_load_content',
245                nonce: diluxMagicTabsData.nonce,
246                tab_id: tabId,
247            }),
248        })
249        .then(response => response.json())
250        .then(data => {
251            if (data.success) {
252                panel.innerHTML = data.data.content;
253                panel.removeAttribute('data-lazy');
254                this.loadedTabs.add(parseInt(panel.dataset.tabIndex));
255                callback();
256            } else {
257                panel.innerHTML = '<div class="dilux-tab-error"><p>Error loading content.</p></div>';
258            }
259        })
260        .catch(error => {
261            panel.innerHTML = '<div class="dilux-tab-error"><p>Error loading content.</p></div>';
262        });
263    }
264
265    handleDeepLinking() {
266        const hash = window.location.hash;
267
268        if (!hash || !hash.startsWith('#tab-')) {
269            return;
270        }
271
272        const slug = hash.replace('#tab-', '');
273
274        if (this.isAccordionVertical) {
275            // Find accordion header with matching slug
276            this.accordionHeaders.forEach((header, index) => {
277                if (header.dataset.tabSlug === slug) {
278                    this.toggleAccordionItem(index);
279                }
280            });
281        } else {
282            // Find tab with matching slug
283            this.tabButtons.forEach((button, index) => {
284                if (button.dataset.tabSlug === slug) {
285                    this.switchTab(index);
286                }
287            });
288        }
289    }
290
291    transformToAccordion() {
292        this.element.classList.add('dilux-magic-tabs-accordion');
293
294        // Create accordion structure
295        const accordion = document.createElement('div');
296        accordion.className = 'dilux-accordion';
297
298        this.tabButtons.forEach((button, index) => {
299            const panel = this.tabPanels[index];
300
301            // Create accordion item
302            const item = document.createElement('div');
303            item.className = 'dilux-accordion-item';
304
305            // Create accordion header
306            const header = document.createElement('button');
307            header.className = 'dilux-accordion-header' + (index === this.activeIndex ? ' active' : '');
308            header.innerHTML = button.innerHTML + '<span class="dilux-accordion-arrow">▼</span>';
309            header.setAttribute('aria-expanded', index === this.activeIndex ? 'true' : 'false');
310
311            // Create accordion content
312            const content = document.createElement('div');
313            content.className = 'dilux-accordion-content' + (index === this.activeIndex ? ' active' : '');
314
315            const contentInner = document.createElement('div');
316            contentInner.className = 'dilux-accordion-content-inner';
317            contentInner.innerHTML = panel.innerHTML;
318
319            content.appendChild(contentInner);
320
321            // Click handler
322            header.addEventListener('click', () => {
323                // Close all other items
324                accordion.querySelectorAll('.dilux-accordion-header').forEach(h => {
325                    if (h !== header) {
326                        h.classList.remove('active');
327                        h.setAttribute('aria-expanded', 'false');
328                        h.nextElementSibling.classList.remove('active');
329                    }
330                });
331
332                // Toggle this item
333                const isActive = header.classList.contains('active');
334                if (isActive) {
335                    header.classList.remove('active');
336                    header.setAttribute('aria-expanded', 'false');
337                    content.classList.remove('active');
338                } else {
339                    header.classList.add('active');
340                    header.setAttribute('aria-expanded', 'true');
341                    content.classList.add('active');
342
343                    // Load content if lazy loading
344                    if (this.lazyLoading && !this.loadedTabs.has(index)) {
345                        this.loadTabContent(panel, () => {
346                            contentInner.innerHTML = panel.innerHTML;
347                            this.loadedTabs.add(index);
348                        });
349                    }
350                }
351            });
352
353            item.appendChild(header);
354            item.appendChild(content);
355            accordion.appendChild(item);
356        });
357
358        this.element.appendChild(accordion);
359    }
360
361    restoreFromAccordion() {
362        this.element.classList.remove('dilux-magic-tabs-accordion');
363
364        // Remove accordion structure
365        const accordion = this.element.querySelector('.dilux-accordion');
366        if (accordion) {
367            accordion.remove();
368        }
369    }
370}
371
372// Initialize all tab groups and accordions on page load
373document.addEventListener('DOMContentLoaded', () => {
374    // Initialize tabs
375    document.querySelectorAll('.dilux-magic-tabs-container').forEach(element => {
376        new DiluxMagicTabs(element);
377    });
378
379    // Initialize accordions
380    document.querySelectorAll('.dilux-magic-accordion-container').forEach(element => {
381        new DiluxMagicTabs(element);
382    });
383});

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.