PageSourceSearch

https://wpamelia.com/wp-content/themes/amelia-theme/amelia-blocks/…/pricing-block-dropdown.js?ver=1790149216

js wpamelia.com collected 2026-10-02 02:29:09 UTC 14,633 bytes, 386 lines download raw bytes

1/**
2 * Pro Domain Dropdown Functionality
3 */
4document.addEventListener('DOMContentLoaded', function() {
5    const dropdowns = document.querySelectorAll('.pricing-card__custom-dropdown');
6
7    function getPromoPercentage(section, cardType, optionNumber) {
8        const percentageKey = `${section}_${cardType}_option${optionNumber}_percentage`;
9        const fromSettings = window.pricingBlockSettings?.[percentageKey];
10
11        if (fromSettings !== undefined && fromSettings !== null && fromSettings !== '') {
12            return parseInt(fromSettings, 10);
13        }
14
15        if (cardType === 'pro' && optionNumber === 1) {
16            return section === 'lifetime' ? 21 : 25;
17        }
18
19        if (cardType === 'pro' && optionNumber === 2) {
20            return 30;
21        }
22
23        return null;
24    }
25
26    function updateDomainPromoDisplay(cardElement, section, cardType, optionNumber) {
27        if (!isCardPromoActive(cardElement)) {
28            return;
29        }
30
31        const percentage = getPromoPercentage(section, cardType, optionNumber);
32
33        if (!percentage) {
34            return;
35        }
36
37        const pillarText = percentage + '% off';
38        const percentagePillar = cardElement.querySelector('.pricing-card__domain-promo-pillar-text');
39        if (percentagePillar) {
40            percentagePillar.textContent = pillarText;
41        }
42
43        const promoBadgeText = cardElement.querySelector('.pricing-card__promo-badge-text');
44        const percentageSpan = promoBadgeText?.querySelector('.percentage');
45        if (percentageSpan) {
46            promoBadgeText.innerHTML =
47                `<span class="percentage">${percentage}%</span><span class="off-text">Off</span>`;
48        }
49    }
50
51    // Initialize on page load
52    dropdowns.forEach(dropdown => {
53        initializeDropdown(dropdown);
54    });
55
56    // Initialize button attributes for Pro/Elite cards on page load
57    initializeButtons();
58
59    // Handle custom dropdown interactions
60    dropdowns.forEach(dropdown => {
61        const selected = dropdown.querySelector('.custom-dropdown__selected');
62        const options = dropdown.querySelectorAll('.custom-dropdown__option');
63        
64        // Toggle dropdown on click
65        selected.addEventListener('click', function(e) {
66            e.stopPropagation();
67            
68            // Check if this dropdown is already open
69            const isCurrentlyOpen = dropdown.classList.contains('open');
70            
71            // Close all dropdowns first
72            closeAllDropdowns();
73            
74            // If this dropdown wasn't open, open it
75            if (!isCurrentlyOpen) {
76                dropdown.classList.add('open');
77            }
78        });
79        
80        // Handle option selection
81        options.forEach(option => {
82            option.addEventListener('click', function(e) {
83                e.stopPropagation();
84                const value = this.dataset.value;
85                const text = this.textContent;
86                
87                // Update selected text
88                selected.textContent = text;
89                
90                // Update selected state
91                options.forEach(opt => opt.classList.remove('selected'));
92                this.classList.add('selected');
93                
94                // Close dropdown
95                dropdown.classList.remove('open');
96                
97                // Trigger pricing update
98                updateDropdown(dropdown, value, { refreshPrices: true });
99            });
100        });
101    });
102
103    // Make entire domain box clickable to open dropdown
104    const domainBoxes = document.querySelectorAll('.pricing-card__domain-info--pro, .pricing-card--elite .pricing-card__domain-info');
105    domainBoxes.forEach(box => {
106        box.addEventListener('click', function(e) {
107            const customDropdown = box.querySelector('.pricing-card__custom-dropdown');
108            if (customDropdown && e.target !== customDropdown && !customDropdown.contains(e.target)) {
109                closeAllDropdowns();
110                customDropdown.classList.toggle('open');
111            }
112        });
113    });
114
115    // Close dropdowns when clicking outside
116    document.addEventListener('click', function(e) {
117        if (!e.target.closest('.pricing-card__domain-info')) {
118            closeAllDropdowns();
119        }
120    });
121
122    function closeAllDropdowns() {
123        dropdowns.forEach(dropdown => {
124            dropdown.classList.remove('open');
125        });
126    }
127    
128    function getDefaultDomainValue(cardElement, cardType) {
129        const fromCard = cardElement?.getAttribute('data-default-domain-value');
130        if (fromCard) {
131            return fromCard;
132        }
133
134        const settingsKey = cardType === 'pro' ? 'pro_default_domain_option' : 'elite_default_domain_option';
135        const optionSetting = window.pricingBlockSettings?.[settingsKey] || 'option2';
136
137        if (cardType === 'pro') {
138            return optionSetting === 'option1' ? '1' : '5';
139        }
140
141        return optionSetting === 'option1' ? '20' : 'unlimited';
142    }
143
144    function isCardPromoActive(cardElement) {
145        return cardElement?.getAttribute('data-card-promo') !== 'no';
146    }
147
148    function getDefaultDomainLabel(cardElement, cardType, defaultValue) {
149        const matchingOption = cardElement?.querySelector(
150            `.custom-dropdown__option[data-value="${defaultValue}"]`
151        );
152        if (matchingOption) {
153            return matchingOption.textContent.trim();
154        }
155
156        if (cardType === 'pro') {
157            return defaultValue === '1'
158                ? (window.ameliaStrings?.['1_domain'] || '1 domain')
159                : (window.ameliaStrings?.['5_domains'] || '5 domains');
160        }
161
162        return defaultValue === '20'
163            ? (window.ameliaStrings?.['20_domains'] || '20 domains')
164            : (window.ameliaStrings?.unlimited_domains || 'Unlimited domains');
165    }
166
167    function initializeButtons() {
168        const proCards = document.querySelectorAll('.pricing-card--pro');
169        const eliteCards = document.querySelectorAll('.pricing-card--elite');
170        
171        [...proCards, ...eliteCards].forEach(card => {
172            const cardType = card.classList.contains('pricing-card--pro') ? 'pro' : 'elite';
173            const section = card.getAttribute('data-card-mode') || 'annual';
174            const defaultValue = getDefaultDomainValue(card, cardType);
175            const optionNumber = (defaultValue === '1' || defaultValue === '20') ? 1 : 2;
176            const pricingKey = `${section}_${cardType}_option${optionNumber}`;
177            const pricingData = window.pricingBlockSettings?.[pricingKey];
178            
179            if (pricingData) {
180                const button = card.querySelector('.pricing-card__button');
181                if (button) {
182                    if (pricingData.button_id) button.setAttribute('id', pricingData.button_id);
183                    if (pricingData.data_plan) button.setAttribute('data-plan', pricingData.data_plan);
184                }
185            }
186        });
187    }
188    
189    function initializeDropdown(dropdown) {
190        const cardElement = dropdown.closest('.pricing-card');
191        const cardType = dropdown.dataset.cardType || (cardElement.classList.contains('pricing-card--pro') ? 'pro' : 'elite');
192        const defaultValue = getDefaultDomainValue(cardElement, cardType);
193        const defaultText = getDefaultDomainLabel(cardElement, cardType, defaultValue);
194
195        const selectedElement = dropdown.querySelector('.custom-dropdown__selected');
196        if (selectedElement) {
197            selectedElement.textContent = defaultText;
198        }
199
200        const options = dropdown.querySelectorAll('.custom-dropdown__option');
201        options.forEach(option => {
202            option.classList.remove('selected');
203            if (option.dataset.value === defaultValue) {
204                option.classList.add('selected');
205            }
206        });
207
208        // Skip full sync when PHP already rendered the correct default (prevents promo badge flash)
209        if (!cardElement.hasAttribute('data-default-domain-value')) {
210            updateDropdown(dropdown, defaultValue, { refreshPrices: false });
211        }
212    }
213    
214    function updateDropdown(dropdown, selectedValue, options) {
215        const refreshPrices = !options || options.refreshPrices !== false;
216        const cardElement = dropdown.closest('.pricing-card');
217        const cardType = dropdown.dataset.cardType || (cardElement.classList.contains('pricing-card--pro') ? 'pro' : 'elite');
218        const section = cardElement.getAttribute('data-card-mode') || 'annual';
219        const optionNumber = (selectedValue === '1' || selectedValue === '20') ? 1 : 2;
220        
221        const option1 = cardElement.querySelector('.pricing-option-1');
222        const option2 = cardElement.querySelector('.pricing-option-2');
223        
224        if (optionNumber === 1) {
225            option1?.classList.add('active');
226            option2?.classList.remove('active');
227        } else {
228            option1?.classList.remove('active');
229            option2?.classList.add('active');
230        }
231
232        updateDomainPromoDisplay(cardElement, section, cardType, optionNumber);
233        
234        const pricingKey = `${section}_${cardType}_option${optionNumber}`;
235        const pricingData = window.pricingBlockSettings?.[pricingKey];
236        const dataPlan = pricingData?.data_plan;
237        
238        if (pricingData) {
239            const buttonId = pricingData.button_id;
240            
241            const button = cardElement.querySelector('.pricing-card__button');
242            if (button) {
243                if (buttonId) button.setAttribute('id', buttonId);
244                if (dataPlan) button.setAttribute('data-plan', dataPlan);
245            }
246        }
247
248        if (refreshPrices) {
249            const activeOption = optionNumber === 1 ? option1 : option2;
250            const priceElements = activeOption
251                ? activeOption.querySelectorAll('.pricing-paddle-price')
252                : cardElement.querySelectorAll('.pricing-paddle-price');
253
254            priceElements.forEach((priceElement) => {
255                if (pricingData && dataPlan) {
256                    priceElement.setAttribute('data-plan', dataPlan);
257                }
258
259                priceElement.removeAttribute('data-billing-price-rendered');
260            });
261
262            if (typeof window.refreshBillingPricePreviews === 'function') {
263                window.refreshBillingPricePreviews();
264            }
265        }
266    }
267
268    // Mobile slider functionality
269    function initializeMobileSlider() {
270        const pricingGrid = document.querySelector('.pricing-block__grid');
271        const navDots = document.querySelectorAll('.nav-dot');
272        const pricingCards = document.querySelectorAll('.pricing-card:not([style*="display: none"])');
273        
274        if (!pricingGrid || !navDots.length || !pricingCards.length) return;
275
276        let currentSlide = 0;
277        let isScrolling = false;
278        let cachedCardWidth = pricingCards[0].offsetWidth + 20;
279
280        pricingGrid.scrollLeft = 0;
281        
282        navDots.forEach((dot, index) => {
283            if (index < pricingCards.length) {
284                dot.style.display = 'block';
285                if (index === 0) dot.classList.add('active');
286            } else {
287                dot.style.display = 'none';
288            }
289        });
290        
291        navDots.forEach((dot, index) => {
292            if (index < pricingCards.length) {
293                dot.addEventListener('click', () => {
294                    scrollToSlide(index);
295                });
296            }
297        });
298        
299        pricingGrid.addEventListener('scroll', () => {
300            if (isScrolling) return;
301            
302            const scrollLeft = pricingGrid.scrollLeft;
303            const slideIndex = Math.round(scrollLeft / cachedCardWidth);
304            
305            if (slideIndex !== currentSlide && slideIndex >= 0 && slideIndex < pricingCards.length) {
306                updateActiveDot(slideIndex);
307            }
308        });
309        
310        let startX = 0;
311        let scrollStart = 0;
312        
313        pricingGrid.addEventListener('touchstart', (e) => {
314            startX = e.touches[0].clientX;
315            scrollStart = pricingGrid.scrollLeft;
316        });
317        
318        pricingGrid.addEventListener('touchmove', (e) => {
319            if (!startX) return;
320            const currentX = e.touches[0].clientX;
321            const diff = startX - currentX;
322            pricingGrid.scrollLeft = scrollStart + diff;
323        });
324        
325        pricingGrid.addEventListener('touchend', () => {
326            startX = 0;
327            scrollStart = 0;
328            const scrollLeft = pricingGrid.scrollLeft;
329            const nearestSlide = Math.round(scrollLeft / cachedCardWidth);
330            scrollToSlide(nearestSlide);
331        });
332        
333        function scrollToSlide(slideIndex) {
334            if (slideIndex < 0 || slideIndex >= pricingCards.length) return;
335            
336            isScrolling = true;
337            const scrollLeft = slideIndex * cachedCardWidth;
338            
339            pricingGrid.scrollTo({
340                left: scrollLeft,
341                behavior: 'smooth'
342            });
343            
344            updateActiveDot(slideIndex);
345            
346            setTimeout(() => {
347                isScrolling = false;
348            }, 300);
349        }
350        
351        function updateActiveDot(slideIndex) {
352            navDots.forEach((dot, index) => {
353                dot.classList.toggle('active', index === slideIndex);
354            });
355            currentSlide = slideIndex;
356        }
357        
358        window.addEventListener('resize', () => {
359            cachedCardWidth = pricingCards[0].offsetWidth + 20;
360        });
361    }
362
363    const isElementorEditor = typeof elementor !== 'undefined' || document.body.classList.contains('elementor-editor-active');
364    let isMobileSliderActive = false;
365    
366    if (!isElementorEditor && window.innerWidth <= 768) {
367        initializeMobileSlider();
368        isMobileSliderActive = true;
369    }
370
371    let resizeTimeout;
372    window.addEventListener('resize', () => {
373        clearTimeout(resizeTimeout);
374        resizeTimeout = setTimeout(() => {
375            if (isElementorEditor) return;
376            
377            const shouldBeMobile = window.innerWidth <= 768;
378            if (shouldBeMobile && !isMobileSliderActive) {
379                initializeMobileSlider();
380                isMobileSliderActive = true;
381            } else if (!shouldBeMobile && isMobileSliderActive) {
382                isMobileSliderActive = false;
383            }
384        }, 150);
385    });
386});

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.