PageSourceSearch

https://www.textmagic.com/wp-content/themes/textmagic-new/gutenber…pricing-2026-accordion.js?ver=v202609220621

js textmagic.com collected 2026-09-24 08:29:57 UTC 6,402 bytes, 157 lines download raw bytes

1/**
2 * Accordion / collapsible for pricing modal 2026 only.
3 * Uses event delegation so it works after AJAX replaces .collapsible-lines content (country change).
4 * Does not run on older pricing pages; accordions.js skips #featuresModal.vesr-2026 for this to handle.
5 *
6 * initPricingSearchClear (below): vanilla JS show/hide + clear for .pricing_search_input inside this modal only
7 * (blog-like UX). Scoped to #featuresModal.vesr-2026 — does not query document-wide selectors.
8 */
9(function () {
10    /**
11     * Show .search__btn-close when input has text; hide when empty. On clear: reset filter UI inside modal
12     * and dispatch keyup so pricing.js pricingSearch re-runs with empty query.
13     */
14    function initPricingSearchClear(modal) {
15        var searchWrap = modal.querySelector('.search--collapsible');
16        if (!searchWrap) return;
17
18        var input = searchWrap.querySelector('input.form-control.pricing_search_input') ||
19            searchWrap.querySelector('.pricing_search_input');
20        var closeBtn = searchWrap.querySelector('.search__btn-close');
21        if (!input || !closeBtn) return;
22
23        function syncCloseButton() {
24            closeBtn.style.display = input.value.length > 0 ? 'flex' : 'none';
25        }
26
27        function resetFeatureSearchDom() {
28            var nothingToShow = modal.querySelector('.nothing-to-show');
29            if (nothingToShow) {
30                nothingToShow.classList.add('hidden');
31            }
32            modal.querySelectorAll('.highlight').forEach(function (el) {
33                el.classList.remove('highlight');
34            });
35            modal.querySelectorAll('.collapsible-line').forEach(function (line) {
36                line.classList.remove('hidden');
37                Array.prototype.slice.call(line.querySelectorAll('.hidden')).forEach(function (node) {
38                    node.classList.remove('hidden');
39                });
40            });
41        }
42
43        input.addEventListener('input', syncCloseButton);
44
45        closeBtn.addEventListener('click', function (e) {
46            e.preventDefault();
47            input.value = '';
48            closeBtn.style.display = 'none';
49            resetFeatureSearchDom();
50            input.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true }));
51        });
52
53        syncCloseButton();
54    }
55
56    function init() {
57        var modal = document.querySelector('#featuresModal.vesr-2026');
58        if (!modal) return;
59
60        initPricingSearchClear(modal);
61
62        var faqList = modal.querySelector('.collapsible-lines');
63        if (!faqList) return;
64
65        var nowActiveElement = null;
66
67        function setAllClosed() {
68            var rows = modal.querySelectorAll('.collapsible-line');
69            var contents = modal.querySelectorAll('.collapsible-content');
70            rows.forEach(function (row) {
71                row.classList.remove('opened');
72            });
73            contents.forEach(function (el) {
74                el.style.height = '0';
75            });
76            var collapseBtn = modal.querySelector('.collapse-btn');
77            if (collapseBtn) {
78                collapseBtn.classList.remove('expand');
79            }
80        }
81
82        function faqClickToElement(header, scrollToElement) {
83            var faqItem = header.parentElement;
84            var isActive = faqItem.classList.contains('opened');
85            var content = header.nextElementSibling;
86
87            if (!isActive) {
88                nowActiveElement = content;
89                if (nowActiveElement) {
90                    nowActiveElement.style.height = nowActiveElement.scrollHeight + 'px';
91                }
92                faqItem.classList.add('opened');
93                if (scrollToElement && faqItem.scrollIntoView) {
94                    setTimeout(function () {
95                        //faqItem.scrollIntoView({ block: 'start', behavior: 'smooth' });
96                    }, 250);
97                }
98            } else {
99                faqItem.classList.remove('opened');
100            }
101        }
102
103        // Initial state: all sections closed, button shows "Expand"
104        setAllClosed();
105
106        // Delegated click: works for initial and AJAX-replaced headers
107        faqList.addEventListener('click', function (e) {
108            var header = e.target.closest('.collapsible-header');
109            if (!header || !faqList.contains(header)) return;
110            faqClickToElement(header, true);
111        });
112
113        // Expand / Collapse all button (capture + stopImmediatePropagation so no other script overrides)
114        var collapseBtn = modal.querySelector('.collapse-btn');
115        if (collapseBtn) {
116            collapseBtn.addEventListener('click', function (e) {
117                e.stopImmediatePropagation();
118                var isExpanded = collapseBtn.classList.contains('expand');
119                var rows = modal.querySelectorAll('.collapsible-line');
120                var contents = modal.querySelectorAll('.collapsible-content');
121                if (isExpanded) {
122                    // All open -> collapse all; button will show "Expand"
123                    collapseBtn.classList.remove('expand');
124                    rows.forEach(function (row) {
125                        row.classList.remove('opened');
126                    });
127                    contents.forEach(function (el) {
128                        el.style.height = '0';
129                    });
130                } else {
131                    // All closed -> expand all; button will show "Collapse"
132                    collapseBtn.classList.add('expand');
133                    rows.forEach(function (row) {
134                        row.classList.add('opened');
135                    });
136                    contents.forEach(function (el) {
137                        el.style.height = el.scrollHeight + 'px';
138                    });
139                }
140            }, true);
141        }
142
143        // Resize: keep open item height correct
144        window.addEventListener('resize', function () {
145            if (nowActiveElement && document.contains(nowActiveElement)) {
146                nowActiveElement.style.height = 'auto';
147                nowActiveElement.style.height = nowActiveElement.scrollHeight + 'px';
148            }
149        }, true);
150    }
151
152    if (document.readyState === 'loading') {
153        document.addEventListener('DOMContentLoaded', init);
154    } else {
155        init();
156    }
157})();

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.