PageSourceSearch

https://ranktoday.com/wp-content/plugins/breakdance/subplugins/bre…eakdance-advanced-accordion.js?bd_ver=2.7.2

js ranktoday.com collected 2026-10-01 12:40:50 UTC 6,022 bytes, 216 lines download raw bytes

1(function () {
2  const accordionButtonSelector =
3    ".bde-accordion__content-wrapper > .bde-accordion__title-tag > button[aria-expanded]";
4
5  const { mergeObjects, isBuilder } = BreakdanceFrontend.utils;
6
7  class BreakdanceAdvancedAccordion {
8    defaultOptions = {
9      accordion: false,
10      openFirst: false,
11      ignoreClickEvent: false
12    };
13
14    constructor(selector, options) {
15      this.selector = selector;
16      this.element = document.querySelector(`${this.selector}`);
17      this.options = mergeObjects(this.defaultOptions, options);
18      this.isBuilder = isBuilder();
19      this.init();
20    }
21
22    init() {
23      this.elements = this.getAccordions();
24      this.handleOnClick = this.onClick.bind(this);
25
26      // Builder: remove click listener in favor of `activateAccordionFromSelector`
27      if (!this.options.ignoreClickEvent) {
28        this.elements.forEach((accordion) => {
29          accordion.addEventListener("click", this.handleOnClick);
30        });
31      }
32
33      if (this.options.openFirst) {
34        this.open(this.elements[0], true);
35      }
36
37      if (this.isBuilder && this.elements.length === 1) {
38        this.open(this.elements[0], true);
39      }
40    }
41
42    getAccordions() {
43      // Return all accordions that are direct children of the selector.
44      // This is to prevent nested accordions from being selected.
45      return Array.from(document.querySelectorAll(`${this.selector} > ${accordionButtonSelector}`));
46    }
47
48    onClick(event) {
49      if (this.options.accordion) {
50        this.closeAllAccordions();
51      }
52      this.toggle(event.currentTarget);
53    }
54
55    isTransitioning(item) {
56      return item.classList.contains("is-collapsing");
57    }
58
59    isActive(item) {
60      return item.classList.contains("is-active");
61    }
62
63    getOpenAccordion() {
64      return this.elements.find((accordion) => this.isActive(this.getAccordionContainer(accordion)));
65    }
66
67    getOpenAccordionIndex() {
68      return this.elements.indexOf(this.getOpenAccordion());
69    }
70
71    getAccordionContent(button) {
72      const controlsId = button.getAttribute("aria-controls");
73      return this.element.querySelector(`#${controlsId}`);
74    }
75
76    getAccordionContainer(button) {
77      return button.closest(".bde-accordion__content-wrapper");
78    }
79
80    async open(button, instant = false) {
81      const containerEl = this.getAccordionContainer(button);
82      const contentEl = this.getAccordionContent(button);
83
84      if (this.isTransitioning(containerEl)) return;
85      if (this.isActive(containerEl)) return;
86
87      const event = new Event("breakdance_play_animations", {bubbles: true});
88      contentEl.dispatchEvent(event);
89
90      const complete = () => {
91        containerEl.classList.add("is-active");
92        containerEl.classList.remove("is-collapsing");
93        contentEl.style.height = "";
94      };
95
96      if (instant) {
97        complete();
98        button.setAttribute("aria-expanded", true);
99        return;
100      }
101
102      containerEl.classList.add("is-collapsing");
103      contentEl.style.height = "0px";
104
105      const endHeight = this.getEndHeight(contentEl);
106      contentEl.style.height = `${endHeight}px`;
107      button.setAttribute("aria-expanded", true);
108
109      await this.onTransitionEnd(contentEl);
110
111      complete();
112    }
113
114    async close(button, instant = false) {
115      const containerEl = this.getAccordionContainer(button);
116      const contentEl = this.getAccordionContent(button);
117
118      if (this.isTransitioning(containerEl)) return;
119      if (!this.isActive(containerEl) || this.options.ignoreClickEvent) return;
120
121      if (instant) {
122        containerEl.classList.remove("is-active");
123        button.setAttribute("aria-expanded", false);
124        return;
125      }
126
127      const endHeight = this.getEndHeight(contentEl);
128      contentEl.style.height = `${endHeight}px`;
129
130      this.reflow(contentEl);
131
132      containerEl.classList.add("is-collapsing");
133      containerEl.classList.remove("is-active");
134      contentEl.style.height = "";
135      button.setAttribute("aria-expanded", false);
136
137      await this.onTransitionEnd(contentEl);
138
139      containerEl.classList.remove("is-collapsing");
140    }
141
142    toggle(button) {
143      const containerEl = this.getAccordionContainer(button);
144
145      if (this.isActive(containerEl)) {
146        this.close(button);
147      } else {
148        this.open(button);
149      }
150    }
151
152    closeAllAccordions() {
153      this.elements.forEach((accordion) => {
154        this.close(accordion);
155      });
156    }
157
158    closeAllItemsExcept(item, instant = false) {
159      this.elements
160        .filter((el) => el !== item)
161        .forEach((el) => this.close(el, instant));
162    }
163
164    destroy() {
165      this.elements.forEach((accordion) => {
166        this.close(accordion, true);
167        accordion.removeEventListener("click", this.handleOnClick);
168      });
169      this.elements = null;
170    }
171
172    getEndHeight(element) {
173      const height = element.getBoundingClientRect().height;
174      return Math.max(element.scrollHeight, height);
175    }
176
177    reflow(element) {
178      element.offsetHeight;
179    }
180
181    onTransitionEnd(item) {
182      const duration = window.getComputedStyle(item)
183        .getPropertyValue("transition-duration");
184
185      // If duration is 0s, transitionend will not fire.
186      if (duration === "0s") {
187        return Promise.resolve();
188      }
189
190      return new Promise((resolve) => {
191        item.addEventListener("transitionend", resolve, {once: true});
192      });
193    }
194
195    update() {
196      this.elements = this.getAccordions();
197
198      this.destroy();
199      this.init();
200    }
201
202    activateAccordionFromSelector(selector) {
203      this.elements = this.getAccordions();
204
205      const buttonEl = selector.querySelector("button[aria-expanded]");
206      const index = this.elements.indexOf(buttonEl);
207
208      const item = index !== -1 ? this.elements[index] : this.elements[0];
209
210      this.closeAllItemsExcept(item, true);
211      this.open(this.elements[index], true);
212    }
213  }
214
215  window.BreakdanceAdvancedAccordion = BreakdanceAdvancedAccordion;
216})();

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.