PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / faq-schema / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/faq-schema/frontend.js

126 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 function toArray(nl) {
3 return Array.prototype.slice.call(nl || []);
4 }
5
6 function initFaqSchema(wrap) {
7 var allowMultiple = wrap.getAttribute('data-allow-multiple') === '1';
8 var speed = parseInt(wrap.getAttribute('data-speed'), 10) || 300;
9 var items = toArray(wrap.querySelectorAll('.bkbg-faq-item'));
10 var questions = toArray(wrap.querySelectorAll('.bkbg-faq-question'));
11
12 // Generate accessible IDs
13 var blockId = 'bkbg-faq-' + Math.random().toString(36).substr(2, 9);
14
15 questions.forEach(function (question, index) {
16 var item = items[index];
17 var answer = item ? item.querySelector('.bkbg-faq-answer') : null;
18
19 var qId = blockId + '-q-' + index;
20 var aId = blockId + '-a-' + index;
21
22 question.id = qId;
23 question.setAttribute('aria-controls', aId);
24
25 if (answer) {
26 answer.id = aId;
27 answer.setAttribute('aria-labelledby', qId);
28
29 // Set proper max-height based on initial state
30 var isActive = item.classList.contains('is-active');
31 if (isActive) {
32 answer.style.maxHeight = answer.scrollHeight + 'px';
33 }
34 }
35
36 question.addEventListener('click', function () {
37 var isExpanded = question.getAttribute('aria-expanded') === 'true';
38
39 if (!allowMultiple && !isExpanded) {
40 // Close all other items
41 items.forEach(function (otherItem, otherIndex) {
42 if (otherIndex !== index) {
43 var otherQ = questions[otherIndex];
44 var otherA = otherItem.querySelector('.bkbg-faq-answer');
45 if (otherQ.getAttribute('aria-expanded') === 'true') {
46 otherQ.setAttribute('aria-expanded', 'false');
47 otherItem.classList.remove('is-active');
48 if (otherA) {
49 otherA.setAttribute('aria-hidden', 'true');
50 otherA.style.maxHeight = '0';
51 }
52 }
53 }
54 });
55 }
56
57 // Toggle current
58 var newState = !isExpanded;
59 question.setAttribute('aria-expanded', newState ? 'true' : 'false');
60 item.classList.toggle('is-active', newState);
61
62 if (answer) {
63 answer.setAttribute('aria-hidden', newState ? 'false' : 'true');
64 if (newState) {
65 // Force repaint to allow transition
66 answer.style.maxHeight = answer.scrollHeight + 'px';
67 // After transition, set to 'none' so auto-height changes work
68 answer.addEventListener('transitionend', function onEnd() {
69 if (item.classList.contains('is-active')) {
70 answer.style.maxHeight = 'none';
71 }
72 answer.removeEventListener('transitionend', onEnd);
73 });
74 } else {
75 // Must set exact height before animating to 0
76 answer.style.maxHeight = answer.scrollHeight + 'px';
77 requestAnimationFrame(function () {
78 requestAnimationFrame(function () {
79 answer.style.maxHeight = '0';
80 });
81 });
82 }
83 }
84 });
85 });
86
87 // Keyboard navigation (arrow keys between questions)
88 questions.forEach(function (question, index) {
89 question.addEventListener('keydown', function (e) {
90 var nextIndex = -1;
91 switch (e.key) {
92 case 'ArrowDown':
93 nextIndex = (index + 1) % questions.length;
94 e.preventDefault();
95 break;
96 case 'ArrowUp':
97 nextIndex = (index - 1 + questions.length) % questions.length;
98 e.preventDefault();
99 break;
100 case 'Home':
101 nextIndex = 0;
102 e.preventDefault();
103 break;
104 case 'End':
105 nextIndex = questions.length - 1;
106 e.preventDefault();
107 break;
108 }
109 if (nextIndex >= 0 && questions[nextIndex]) {
110 questions[nextIndex].focus();
111 }
112 });
113 });
114 }
115
116 function init() {
117 toArray(document.querySelectorAll('.bkbg-faq-wrap')).forEach(initFaqSchema);
118 }
119
120 if (document.readyState === 'loading') {
121 document.addEventListener('DOMContentLoaded', init);
122 } else {
123 init();
124 }
125 })();
126