PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.65
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.65
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Unfold / script.js

script.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.65, at includes/widgets/Unfold/script.js

291 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "use strict";
2
3 (() => {
4 const easingMap = {
5 linear: (t) => t,
6 ease: (t) => 0.5 * (1 - Math.cos(Math.PI * t)),
7 "ease-in": (t) => t * t,
8 "ease-out": (t) => t * (2 - t),
9 "ease-in-out": (t) => {
10 return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
11 }
12 };
13
14 const cssEasing = (name) => {
15 if (["linear", "ease", "ease-in", "ease-out", "ease-in-out"].includes(name)) {
16 return name;
17 }
18 return "ease";
19 };
20
21 const getBreakpoints = () => {
22 const defaults = { md: 1025, lg: 1440 };
23 const config = (window.elementorFrontend && window.elementorFrontend.config && window.elementorFrontend.config.breakpoints) || {};
24 return { ...defaults, ...config };
25 };
26
27 const getCurrentDevice = () => {
28 const width = window.innerWidth;
29 const breakpoints = getBreakpoints();
30
31 if (width <= (breakpoints.md || 1025)) {
32 return "mobile";
33 }
34 if (width <= (breakpoints.lg || 1440)) {
35 return "tablet";
36 }
37 return "desktop";
38 };
39
40 const measureFullHeight = (content) => {
41 const prevHeight = content.style.height;
42 const prevMaxHeight = content.style.maxHeight;
43 content.style.height = "auto";
44 content.style.maxHeight = "none";
45 const height = content.scrollHeight;
46 content.style.height = prevHeight;
47 content.style.maxHeight = prevMaxHeight;
48 return height;
49 };
50
51 const getFoldHeight = (content, unit) => {
52 const device = getCurrentDevice();
53 const key = device === "mobile" ? "foldHeightMobile" : device === "tablet" ? "foldHeightTablet" : "foldHeightDesktop";
54 const value = parseFloat(content.dataset[key] || content.dataset.foldHeightDesktop || "0");
55 const fullHeight = measureFullHeight(content);
56
57 if (unit === "percent") {
58 return Math.max(0, Math.min(fullHeight, (fullHeight * value) / 100));
59 }
60 return Math.max(0, Math.min(fullHeight, value));
61 };
62
63 const setFadeState = (fadeEl, fadeOnlyFolded, expanded, fadeHeight) => {
64 if (!fadeEl) {
65 return;
66 }
67 if (typeof fadeHeight === "number" && !Number.isNaN(fadeHeight)) {
68 fadeEl.style.setProperty("--ka-unfold-fade-height", `${fadeHeight}px`);
69 fadeEl.style.height = `${fadeHeight}px`;
70 }
71 if (fadeOnlyFolded && expanded) {
72 fadeEl.classList.add("king-addons-unfold__fade--hidden");
73 } else {
74 fadeEl.classList.remove("king-addons-unfold__fade--hidden");
75 }
76 };
77
78 const animateHeight = (content, from, to, duration, easing, type, onComplete) => {
79 const resolvedDuration = Math.max(0, duration);
80 const easeFn = easingMap[easing] || easingMap.ease;
81
82 if (resolvedDuration === 0) {
83 content.style.height = "";
84 content.style.maxHeight = `${to}px`;
85 if (onComplete) {
86 onComplete();
87 }
88 return;
89 }
90
91 if (type === "max-height") {
92 content.style.transition = `max-height ${resolvedDuration}s ${cssEasing(easing)}`;
93 requestAnimationFrame(() => {
94 content.style.maxHeight = `${to}px`;
95 });
96 setTimeout(() => {
97 content.style.transition = "";
98 if (onComplete) {
99 onComplete();
100 }
101 }, resolvedDuration * 1000);
102 return;
103 }
104
105 let start = null;
106 const step = (timestamp) => {
107 if (!start) {
108 start = timestamp;
109 }
110 const progress = Math.min((timestamp - start) / (resolvedDuration * 1000), 1);
111 const eased = easeFn(progress);
112 const current = from + (to - from) * eased;
113 content.style.height = `${current}px`;
114 if (progress < 1) {
115 requestAnimationFrame(step);
116 } else {
117 content.style.height = "";
118 content.style.maxHeight = `${to}px`;
119 if (onComplete) {
120 onComplete();
121 }
122 }
123 };
124 requestAnimationFrame(step);
125 };
126
127 const updateButtonState = (button, expanded) => {
128 if (!button) {
129 return;
130 }
131 const textEl = button.querySelector(".king-addons-unfold__text");
132 const iconUnfold = button.querySelector(".king-addons-unfold__icon--unfold");
133 const iconFold = button.querySelector(".king-addons-unfold__icon--fold");
134
135 if (textEl) {
136 textEl.textContent = expanded ? button.dataset.foldText : button.dataset.unfoldText;
137 }
138
139 if (iconUnfold && iconFold) {
140 if (expanded) {
141 iconUnfold.setAttribute("aria-hidden", "true");
142 iconUnfold.classList.add("king-addons-unfold__icon--hidden");
143 iconFold.setAttribute("aria-hidden", "false");
144 iconFold.classList.remove("king-addons-unfold__icon--hidden");
145 } else {
146 iconFold.setAttribute("aria-hidden", "true");
147 iconFold.classList.add("king-addons-unfold__icon--hidden");
148 iconUnfold.setAttribute("aria-hidden", "false");
149 iconUnfold.classList.remove("king-addons-unfold__icon--hidden");
150 }
151 }
152
153 button.setAttribute("aria-expanded", expanded ? "true" : "false");
154 };
155
156 const applyInitialState = (wrapper, content, fadeEl, button) => {
157 const unit = wrapper.dataset.foldUnit || "percent";
158 const initialState = wrapper.dataset.initialState === "unfolded" ? "unfolded" : "folded";
159 const fadeOnlyFolded = wrapper.dataset.fadeOnlyFolded === "true";
160 const fadeHeight = parseFloat(wrapper.dataset.fadeHeight || "30");
161 const fullHeight = measureFullHeight(content);
162 const foldHeight = getFoldHeight(content, unit);
163 const expanded = initialState === "unfolded";
164
165 content.style.overflow = "hidden";
166 if (initialState === "folded") {
167 content.style.height = "";
168 content.style.maxHeight = `${foldHeight}px`;
169 } else {
170 content.style.height = "";
171 content.style.maxHeight = `${fullHeight}px`;
172 }
173
174 wrapper.classList.toggle("king-addons-unfold--folded", !expanded);
175 wrapper.classList.toggle("king-addons-unfold--unfolded", expanded);
176 content.setAttribute("aria-hidden", expanded ? "false" : "true");
177
178 if (button) {
179 updateButtonState(button, expanded);
180 }
181 setFadeState(fadeEl, fadeOnlyFolded, expanded, fadeHeight);
182 };
183
184 const scrollIntoView = (wrapper, offset) => {
185 const top = wrapper.getBoundingClientRect().top + window.scrollY - offset;
186 window.scrollTo({
187 top,
188 behavior: "smooth"
189 });
190 };
191
192 const initInstance = (wrapper) => {
193 const content = wrapper.querySelector(".king-addons-unfold__content");
194 if (!content) {
195 return;
196 }
197 const fadeEl = wrapper.querySelector(".king-addons-unfold__fade");
198 const button = wrapper.querySelector(".king-addons-unfold__button");
199
200 const unit = wrapper.dataset.foldUnit || "percent";
201 const fadeOnlyFolded = wrapper.dataset.fadeOnlyFolded === "true";
202 const fadeHeight = parseFloat(wrapper.dataset.fadeHeight || "30");
203 const animateType = wrapper.dataset.animateType || "auto-to-fixed";
204 const scrollAfter = wrapper.dataset.scrollAfter === "true";
205 const scrollOffset = parseInt(wrapper.dataset.scrollOffset || "0", 10) || 0;
206 const foldDuration = parseFloat(wrapper.dataset.foldDuration || "0.5");
207 const unfoldDuration = parseFloat(wrapper.dataset.unfoldDuration || "0.5");
208 const foldEasing = wrapper.dataset.foldEasing || "ease";
209 const unfoldEasing = wrapper.dataset.unfoldEasing || "ease";
210
211 applyInitialState(wrapper, content, fadeEl, button);
212
213 const toggle = (expand) => {
214 const fullHeight = measureFullHeight(content);
215 const foldHeight = getFoldHeight(content, unit);
216 const targetHeight = expand ? fullHeight : foldHeight;
217 const currentHeight = content.getBoundingClientRect().height;
218 const duration = expand ? unfoldDuration : foldDuration;
219 const easing = expand ? unfoldEasing : foldEasing;
220
221 content.style.overflow = "hidden";
222
223 animateHeight(
224 content,
225 currentHeight,
226 targetHeight,
227 duration,
228 easing,
229 animateType,
230 () => {
231 wrapper.classList.toggle("king-addons-unfold--folded", !expand);
232 wrapper.classList.toggle("king-addons-unfold--unfolded", expand);
233 content.setAttribute("aria-hidden", expand ? "false" : "true");
234 setFadeState(fadeEl, fadeOnlyFolded, expand, fadeHeight);
235 updateButtonState(button, expand);
236 if (expand && scrollAfter) {
237 scrollIntoView(wrapper, scrollOffset);
238 }
239 }
240 );
241 };
242
243 if (button) {
244 button.addEventListener("click", () => {
245 const isExpanded = wrapper.classList.contains("king-addons-unfold--unfolded");
246 toggle(!isExpanded);
247 });
248 }
249
250 let resizeTimeout = null;
251 const handleResize = () => {
252 const isExpanded = wrapper.classList.contains("king-addons-unfold--unfolded");
253 const fullHeight = measureFullHeight(content);
254 const foldHeight = getFoldHeight(content, unit);
255 const target = isExpanded ? fullHeight : foldHeight;
256 content.style.transition = "";
257 content.style.maxHeight = `${target}px`;
258 setFadeState(fadeEl, fadeOnlyFolded, isExpanded, fadeHeight);
259 };
260
261 window.addEventListener("resize", () => {
262 clearTimeout(resizeTimeout);
263 resizeTimeout = setTimeout(handleResize, 150);
264 });
265 };
266
267 const initScope = (scope) => {
268 const root = scope || document;
269 root.querySelectorAll(".king-addons-unfold").forEach((wrapper) => {
270 initInstance(wrapper);
271 });
272 };
273
274 document.addEventListener("DOMContentLoaded", () => {
275 initScope(document);
276 });
277
278 if (window.elementorFrontend) {
279 window.elementorFrontend.hooks.addAction("frontend/element_ready/king-addons-unfold.default", ($scope) => {
280 const scopeEl = $scope && $scope[0] ? $scope[0] : $scope;
281 initScope(scopeEl);
282 });
283 }
284 })();
285
286
287
288
289
290
291