1(function () { 2 const { mergeObjects } = BreakdanceFrontend.utils; 3 4 class BreakdanceFaq { 5 options = { 6 accordion: false, 7 openFirst: false, 8 }; 9 10 constructor(selector, options) { 11 this.selector = selector; 12 this.options = mergeObjects(this.options, options || {}); 13 this.init(); 14 } 15 16 toggleItem(event, item) { 17 const targetEl = item ? item : event.target; 18 const faqEl = targetEl.closest(".bde-faq__item"); 19 const isActive = faqEl.classList.contains("is-active"); 20 21 if (this.options.accordion) { 22 this.closeAllItemsExcept(targetEl); 23 } 24 25 if (isActive) { 26 this.closeItem(targetEl); 27 } else { 28 this.showItem(targetEl); 29 } 30 } 31 32 closeAllItems() { 33 this.elements.forEach((item) => this.closeItem(item)); 34 } 35 36 closeAllItemsExcept(item) { 37 this.elements 38 .filter((el) => el !== item) 39 .forEach((el) => this.closeItem(el)); 40 } 41 42 isTransitioning(item) { 43 return item.classList.contains("is-collapsing"); 44 } 45 46 isActive(item) { 47 return item.classList.contains("is-active"); 48 } 49 50 async closeItem(item) { 51 const faqEl = item.closest(".bde-faq__item"); 52 53 if (this.isTransitioning(faqEl)) return; 54 if (!this.isActive(faqEl)) return; 55 56 const faqButton = faqEl.querySelector(".bde-faq__question"); 57 const faqContent = faqEl.querySelector(".bde-faq__answer"); 58 59 const endHeight = this.getEndHeight(faqContent); 60 faqContent.style.height = `${endHeight}px`; 61 62 this.reflow(faqContent); 63 64 faqEl.classList.add("is-collapsing"); 65 faqEl.classList.remove("is-active"); 66 faqContent.style.height = ""; 67 faqButton.setAttribute("aria-expanded", false); 68 69 await this.onTransitionEnd(faqContent); 70 71 faqEl.classList.remove("is-collapsing"); 72 } 73 74 async showItem(item, instant = false) { 75 const faqEl = item.closest(".bde-faq__item"); 76 77 if (this.isTransitioning(faqEl)) return; 78 if (this.isActive(faqEl)) return; 79 80 const faqButton = faqEl.querySelector(".bde-faq__question"); 81 const faqContent = faqEl.querySelector(".bde-faq__answer"); 82 83 const complete = () => { 84 faqEl.classList.add("is-active"); 85 faqEl.classList.remove("is-collapsing"); 86 faqContent.style.height = ""; 87 }; 88 89 if (instant) { 90 complete(); 91 faqButton.setAttribute("aria-expanded", true); 92 return; 93 } 94 95 faqEl.classList.add("is-collapsing"); 96 faqContent.style.height = "0px"; 97 98 const endHeight = this.getEndHeight(faqContent); 99 faqContent.style.height = `${endHeight}px`; 100 faqButton.setAttribute("aria-expanded", true); 101 102 await this.onTransitionEnd(faqContent); 103 104 complete(); 105 } 106 107 getEndHeight(element) { 108 const height = element.getBoundingClientRect().height; 109 return Math.max(element.scrollHeight, height); 110 } 111 112 reflow(element) { 113 element.offsetHeight; 114 } 115 116 update(options = {}) { 117 this.options = mergeObjects(this.options, options); 118 this.destroy(); 119 this.init(); 120 } 121 122 openFirst() { 123 if (!this.elements[0]) return; 124 this.showItem(this.elements[0], true); 125 } 126 127 onTransitionEnd(item) { 128 const duration = window.getComputedStyle(item) 129 .getPropertyValue("transition-duration"); 130 131 // If duration is 0s, transitionend will not fire. 132 if (duration === "0s") { 133 return Promise.resolve(); 134 } 135 136 return new Promise((resolve) => { 137 item.addEventListener("transitionend", resolve, { once: true }); 138 }); 139 } 140 141 destroy() { 142 this.elements = Array.from(document.querySelectorAll( 143 `${this.selector} .js-faq-item` 144 )); 145 146 if (!this.elements) return; 147 148 this.closeAllItems(); 149 this.elements.forEach((item) => 150 item.removeEventListener("click", this.onClick) 151 ); 152 } 153 154 bindClickListeners() { 155 this.onClick = this.toggleItem.bind(this); 156 this.elements.forEach((item) => { 157 item.addEventListener("click", this.onClick); 158 }); 159 } 160 161 init() { 162 this.elements = Array.from(document.querySelectorAll( 163 `${this.selector} .js-faq-item` 164 )); 165 166 if (this.options.openFirst === true) { 167 this.openFirst(); 168 } 169 170 this.bindClickListeners(); 171 } 172 } 173 174 window.BreakdanceFaq = BreakdanceFaq; 175})();
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.