PageSourceSearch

https://w4u.in/assets/ai-assistant/bw-faq-accordion.js?v=1790771568

js w4u.in collected 2026-10-01 15:55:40 UTC 9,527 bytes, 286 lines download raw bytes

1/**
2 * FAQ accordion — click question to show/hide answer (editor + live pages).
3 * Uses document-level delegation so ContentBox / new sections do not break handlers.
4 */
5(function (global) {
6    'use strict';
7
8    /* Footer + page templates may both include this file — only bind handlers once. */
9    if (global.__bwFaqAccordionBooted) {
10        return;
11    }
12    global.__bwFaqAccordionBooted = true;
13
14    var preparedLists = typeof WeakSet !== 'undefined' ? new WeakSet() : null;
15
16    function isEditorMode() {
17        if (global.BW_IS_CONTENTBOX_EDITOR || global.BW_IS_AIBOX_EDITOR) {
18            return true;
19        }
20        if (global.BwIsContentboxEditor) {
21            return global.BwIsContentboxEditor();
22        }
23        if (global.BwContentboxClickfix && typeof global.BwContentboxClickfix.isEditorMode === 'function') {
24            return global.BwContentboxClickfix.isEditorMode();
25        }
26        if (document.body && document.body.classList.contains('bw-page-editor')) {
27            return true;
28        }
29        return false;
30    }
31
32    function findAnswer(li) {
33        for (var i = 0; i < li.children.length; i++) {
34            var ch = li.children[i];
35            if (ch.nodeType !== 1) {
36                continue;
37            }
38            if (
39                ch.classList.contains('answer') ||
40                ch.classList.contains('bw-faq-answer') ||
41                ch.classList.contains('faq-answer')
42            ) {
43                return ch;
44            }
45        }
46        return null;
47    }
48
49    function findQuestion(li) {
50        for (var i = 0; i < li.children.length; i++) {
51            var ch = li.children[i];
52            if (ch.nodeType !== 1) {
53                continue;
54            }
55            var tag = ch.tagName;
56            if (tag === 'H3' || tag === 'H4' || ch.classList.contains('faq-question')) {
57                return ch;
58            }
59        }
60        return null;
61    }
62
63    function closeAllInList(ul) {
64        ul.querySelectorAll(':scope > li').forEach(function (li) {
65            var answer = findAnswer(li);
66            var question = findQuestion(li);
67            if (answer) {
68                answer.style.removeProperty('display');
69            }
70            if (question) {
71                question.classList.remove('bw-faq-open');
72                question.setAttribute('aria-expanded', 'false');
73            }
74            li.classList.remove('active');
75        });
76    }
77
78    function prepareAccordionList(ul) {
79        if (!ul) {
80            return;
81        }
82        var editor = isEditorMode();
83        if (!editor && preparedLists && preparedLists.has(ul)) {
84            return;
85        }
86        if (preparedLists) {
87            preparedLists.add(ul);
88        }
89        ul.removeAttribute('data-bw-faq-prepared');
90
91        ul.querySelectorAll(':scope > li').forEach(function (li) {
92            var question = findQuestion(li);
93            var answer = findAnswer(li);
94            if (!question || !answer) {
95                return;
96            }
97            li.classList.remove('active');
98            question.classList.remove('bw-faq-open');
99            question.setAttribute('aria-expanded', 'false');
100            answer.style.removeProperty('display');
101            question.style.cursor = 'pointer';
102            question.setAttribute('role', 'button');
103            if (!question.hasAttribute('tabindex')) {
104                question.setAttribute('tabindex', '0');
105            }
106        });
107    }
108
109    function toggleAccordionItem(li) {
110        var ul = li.parentElement;
111        if (!ul || !ul.classList.contains('accordion-list')) {
112            return;
113        }
114        var answer = findAnswer(li);
115        var question = findQuestion(li);
116        if (!answer || !question) {
117            return;
118        }
119        var isOpen = li.classList.contains('active');
120        if (isOpen) {
121            li.classList.remove('active');
122            question.classList.remove('bw-faq-open');
123            question.setAttribute('aria-expanded', 'false');
124        } else {
125            li.classList.add('active');
126            question.classList.add('bw-faq-open');
127            question.setAttribute('aria-expanded', 'true');
128        }
129    }
130
131    var delegatedDocs = typeof WeakSet !== 'undefined' ? new WeakSet() : null;
132    var delegatedBoundLegacy = false;
133
134    function bindDelegation(doc) {
135        doc = doc || document;
136        if (delegatedDocs) {
137            if (delegatedDocs.has(doc)) {
138                return;
139            }
140            delegatedDocs.add(doc);
141        } else if (doc === document) {
142            if (delegatedBoundLegacy) {
143                return;
144            }
145            delegatedBoundLegacy = true;
146        }
147
148        doc.addEventListener('click', function (e) {
149            if (isEditorMode()) {
150                return;
151            }
152            if (e.target.closest('a, button, input, select, textarea, label')) {
153                return;
154            }
155            var li = e.target.closest('ul.accordion-list > li');
156            if (!li) {
157                return;
158            }
159            var ul = li.closest('ul.accordion-list');
160            if (!ul || !findQuestion(li) || !findAnswer(li)) {
161                return;
162            }
163            e.preventDefault();
164            e.stopPropagation();
165            toggleAccordionItem(li);
166        }, true);
167
168        doc.addEventListener('keydown', function (e) {
169            if (isEditorMode()) {
170                return;
171            }
172            if (e.key !== 'Enter' && e.key !== ' ') {
173                return;
174            }
175            var question = e.target.closest('ul.accordion-list > li > h3, ul.accordion-list > li > h4, ul.accordion-list > li > .faq-question');
176            if (!question) {
177                return;
178            }
179            e.preventDefault();
180            var li = question.parentElement;
181            if (li) {
182                toggleAccordionItem(li);
183            }
184        }, true);
185    }
186
187    function bindStaticFaqItems(root) {
188        var doc = (root && root.nodeType === 9) ? root : ((root && root.ownerDocument) || document);
189        root.querySelectorAll('.faq-item').forEach(function (item) {
190            if (item.closest('ul.accordion-list') || item.getAttribute('data-bw-faq-bound') === '1') {
191                return;
192            }
193            var h = item.querySelector('h3, h4, .faq-question');
194            if (!h) {
195                return;
196            }
197            var bodyNodes = [];
198            Array.prototype.forEach.call(item.childNodes, function (ch) {
199                if (ch.nodeType !== 1) {
200                    return;
201                }
202                if (ch === h || ch.tagName === 'H3' || ch.tagName === 'H4' || ch.classList.contains('faq-question')) {
203                    return;
204                }
205                bodyNodes.push(ch);
206            });
207            if (bodyNodes.length === 0) {
208                return;
209            }
210            item.setAttribute('data-bw-faq-bound', '1');
211            var wrap = doc.createElement('div');
212            wrap.className = 'answer';
213            bodyNodes.forEach(function (n) {
214                wrap.appendChild(n);
215            });
216            item.appendChild(wrap);
217            item.classList.remove('active');
218            h.style.cursor = 'pointer';
219            h.addEventListener('click', function (ev) {
220                if (isEditorMode()) {
221                    return;
222                }
223                ev.preventDefault();
224                ev.stopPropagation();
225                var open = item.classList.contains('active');
226                root.querySelectorAll('.faq-item').forEach(function (x) {
227                    x.classList.remove('active');
228                });
229                root.querySelectorAll('.faq-item h3, .faq-item h4, .faq-item .faq-question').forEach(function (q) {
230                    q.classList.remove('bw-faq-open');
231                });
232                if (!open) {
233                    item.classList.add('active');
234                    h.classList.add('bw-faq-open');
235                }
236            });
237        });
238    }
239
240    function prepareDetailsFaqs(root) {
241        root.querySelectorAll('details.bw-faq-item[open]').forEach(function (el) {
242            if (!isEditorMode()) {
243                el.removeAttribute('open');
244            }
245        });
246    }
247
248    function init(root) {
249        root = root || document;
250        var doc = (root.nodeType === 9) ? root : (root.ownerDocument || document);
251        var scope = (root.nodeType === 9) ? (root.body || root) : root;
252        bindDelegation(doc);
253        scope.querySelectorAll('ul.accordion-list').forEach(prepareAccordionList);
254        bindStaticFaqItems(scope);
255        prepareDetailsFaqs(scope);
256    }
257
258    function watch() {
259        init(document);
260        if (typeof MutationObserver === 'undefined') {
261            return;
262        }
263        var obs = new MutationObserver(function () {
264            init(document);
265        });
266        var target = document.querySelector('.is-wrapper') || document.body;
267        if (target) {
268            obs.observe(target, { childList: true, subtree: true });
269        }
270    }
271
272    global.BwFaqAccordion = { init: init, watch: watch };
273
274    function boot() {
275        watch();
276        window.addEventListener('load', function () {
277            init(document);
278        });
279    }
280
281    if (document.readyState === 'loading') {
282        document.addEventListener('DOMContentLoaded', boot);
283    } else {
284        boot();
285    }
286})(typeof window !== 'undefined' ? window : this);

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.