PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.83
51.1.84 51.1.85 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 All 39 releases
← All changes | includes/widgets/Content_Ticker/script.js +207 -57 51.1.3751.1.83 View file →
@@ -27,10 +27,11 @@
27 27 const sliderColumnsWideScreen = getClassNumber(/columns--widescreen(\d)/, sliderColumnsDesktop);
28 28 const sliderColumnsLaptop = getClassNumber(/columns--laptop(\d)/, sliderColumnsDesktop);
29 29 const sliderColumnsTablet = getClassNumber(/columns--tablet(\d)/, 2);
30 30 const sliderColumnsTabletExtra = getClassNumber(/columns--tablet_extra(\d)/, sliderColumnsTablet);
31 - const sliderColumnsMobileExtra = getClassNumber(/columns--mobile_extra(\d)/, sliderColumnsTablet);
32 31 const sliderColumnsMobile = getClassNumber(/columns--mobile(\d)/, 1);
32 + // Mobile extra should fall back to mobile, not tablet.
33 + const sliderColumnsMobileExtra = getClassNumber(/columns--mobile_extra(\d)/, sliderColumnsMobile);
33 34
34 35 // Slides to scroll logic if the slider effect is "hr-slide"
35 36 const sliderSlidesToScroll =
36 37 dataSlideEffect === "hr-slide"
@@ -43,74 +44,223 @@
43 44 // Short helper to decide slidesToShow and slidesToScroll
44 45 const getSlidesToShow = columns => (isTypingOrFade ? 1 : columns);
45 46 const getSlidesToScroll = columns => (sliderSlidesToScroll > columns ? 1 : sliderSlidesToScroll);
46 47
48 + const isMeasurable = ($el) => {
49 + if (!$el || !$el.length) {
50 + return false;
51 + }
52 + // :visible can be true even with width 0 depending on CSS.
53 + return $el.is(":visible") && $el.outerWidth() > 0;
54 + };
55 +
47 56 // Slick settings with breakpoints
48 - $contentTickerSlider.slick({
49 - appendArrows: $element.find(".king-addons-ticker-slider-controls"),
50 - slidesToShow: sliderColumnsDesktop,
51 - responsive: [
52 - {
53 - breakpoint: 10000,
54 - settings: {
55 - slidesToShow: getSlidesToShow(sliderColumnsWideScreen),
56 - slidesToScroll: getSlidesToScroll(sliderColumnsWideScreen),
57 - fade: isTypingOrFade,
57 + const normalizeBool = (value) => {
58 + return value === true || value === 1 || value === "1" || value === "true" || value === "yes";
59 + };
60 +
61 + const slickOptionsFromAttr = (() => {
62 + const raw = $contentTickerSlider.attr("data-slick-options");
63 + if (!raw) {
64 + return {};
65 + }
66 +
67 + try {
68 + const parsed = JSON.parse(raw);
69 + if (parsed && typeof parsed === "object") {
70 + // Normalize Elementor switcher values.
71 + if ("pauseOnHover" in parsed) {
72 + parsed.pauseOnHover = normalizeBool(parsed.pauseOnHover);
73 + }
74 + if ("autoplay" in parsed) {
75 + parsed.autoplay = normalizeBool(parsed.autoplay);
76 + }
77 + if ("infinite" in parsed) {
78 + parsed.infinite = normalizeBool(parsed.infinite);
79 + }
80 + if ("rtl" in parsed) {
81 + parsed.rtl = normalizeBool(parsed.rtl);
82 + }
83 + if ("arrows" in parsed) {
84 + parsed.arrows = normalizeBool(parsed.arrows);
85 + }
86 + if ("vertical" in parsed) {
87 + parsed.vertical = normalizeBool(parsed.vertical);
88 + }
89 +
90 + if ("autoplaySpeed" in parsed) {
91 + parsed.autoplaySpeed = parseInt(parsed.autoplaySpeed, 10) || 0;
92 + }
93 + if ("speed" in parsed) {
94 + parsed.speed = parseInt(parsed.speed, 10) || 0;
95 + }
96 +
97 + return parsed;
98 + }
99 + } catch (e) {
100 + // Ignore invalid JSON.
101 + }
102 + return {};
103 + })();
104 +
105 + const initOrRefreshSlick = () => {
106 + if (!$contentTickerSlider.length) {
107 + return;
108 + }
109 +
110 + // If initialized while hidden, Slick can calculate wrong widths.
111 + // Re-init only when element has a measurable width.
112 + if (!isMeasurable($contentTickerSlider)) {
113 + return;
114 + }
115 +
116 + // Prevent duplicate initialization when Elementor re-renders.
117 + if ($contentTickerSlider.hasClass("slick-initialized")) {
118 + try {
119 + $contentTickerSlider.slick("setPosition");
120 + } catch (e) {
121 + // ignore
122 + }
123 + return;
124 + }
125 +
126 + $contentTickerSlider.slick({
127 + ...slickOptionsFromAttr,
128 + appendArrows: $element.find(".king-addons-ticker-slider-controls"),
129 + // Base (>= 2400px) uses widescreen columns when provided.
130 + slidesToShow: getSlidesToShow(sliderColumnsWideScreen),
131 + slidesToScroll: getSlidesToScroll(sliderColumnsWideScreen),
132 + fade: isTypingOrFade,
133 + responsive: [
134 + {
135 + breakpoint: 2399,
136 + settings: {
137 + slidesToShow: getSlidesToShow(sliderColumnsDesktop),
138 + slidesToScroll: getSlidesToScroll(sliderColumnsDesktop),
139 + fade: isTypingOrFade,
140 + },
58 141 },
59 - },
60 - {
61 - breakpoint: 2399,
62 - settings: {
63 - slidesToShow: getSlidesToShow(sliderColumnsDesktop),
64 - slidesToScroll: getSlidesToScroll(sliderColumnsDesktop),
65 - fade: isTypingOrFade,
142 + {
143 + breakpoint: 1221,
144 + settings: {
145 + slidesToShow: getSlidesToShow(sliderColumnsLaptop),
146 + slidesToScroll: getSlidesToScroll(sliderColumnsLaptop),
147 + fade: isTypingOrFade,
148 + },
66 149 },
67 - },
68 - {
69 - breakpoint: 1221,
70 - settings: {
71 - slidesToShow: getSlidesToShow(sliderColumnsLaptop),
72 - slidesToScroll: getSlidesToScroll(sliderColumnsLaptop),
73 - fade: isTypingOrFade,
150 + {
151 + breakpoint: 1200,
152 + settings: {
153 + slidesToShow: getSlidesToShow(sliderColumnsTabletExtra),
154 + slidesToScroll: getSlidesToScroll(sliderColumnsTabletExtra),
155 + fade: isTypingOrFade,
156 + },
74 157 },
75 - },
76 - {
77 - breakpoint: 1200,
78 - settings: {
79 - slidesToShow: getSlidesToShow(sliderColumnsTabletExtra),
80 - slidesToScroll: getSlidesToScroll(sliderColumnsTabletExtra),
81 - fade: isTypingOrFade,
158 + {
159 + breakpoint: 1024,
160 + settings: {
161 + slidesToShow: getSlidesToShow(sliderColumnsTablet),
162 + slidesToScroll: getSlidesToScroll(sliderColumnsTablet),
163 + fade: isTypingOrFade,
164 + },
82 165 },
83 - },
84 - {
85 - breakpoint: 1024,
86 - settings: {
87 - slidesToShow: getSlidesToShow(sliderColumnsTablet),
88 - slidesToScroll: getSlidesToScroll(sliderColumnsTablet),
89 - fade: isTypingOrFade,
166 + {
167 + breakpoint: 880,
168 + settings: {
169 + slidesToShow: getSlidesToShow(sliderColumnsMobileExtra),
170 + slidesToScroll: getSlidesToScroll(sliderColumnsMobileExtra),
171 + fade: isTypingOrFade,
172 + },
90 173 },
91 - },
92 - {
93 - breakpoint: 880,
94 - settings: {
95 - slidesToShow: getSlidesToShow(sliderColumnsMobileExtra),
96 - slidesToScroll: getSlidesToScroll(sliderColumnsMobileExtra),
97 - fade: isTypingOrFade,
174 + {
175 + breakpoint: 768,
176 + settings: {
177 + slidesToShow: getSlidesToShow(sliderColumnsMobile),
178 + slidesToScroll: getSlidesToScroll(sliderColumnsMobile),
179 + fade: isTypingOrFade,
180 + },
98 181 },
99 - },
100 - {
101 - breakpoint: 768,
102 - settings: {
103 - slidesToShow: getSlidesToShow(sliderColumnsMobile),
104 - slidesToScroll: getSlidesToScroll(sliderColumnsMobile),
105 - fade: isTypingOrFade,
106 - },
107 - },
108 - ],
182 + ],
183 + });
184 +
185 + // Force a layout pass right after init.
186 + try {
187 + $contentTickerSlider.slick("setPosition");
188 + } catch (e) {
189 + // ignore
190 + }
191 + };
192 +
193 + const retryInit = (attempt = 0) => {
194 + if (attempt > 40) {
195 + return;
196 + }
197 + initOrRefreshSlick();
198 + if (!$contentTickerSlider.hasClass("slick-initialized")) {
199 + setTimeout(() => retryInit(attempt + 1), 50);
200 + }
201 + };
202 +
203 + // If slider is already initialized (e.g. rendered by cached HTML), ensure it positions correctly.
204 + if ($contentTickerSlider.hasClass("slick-initialized")) {
205 + try {
206 + $contentTickerSlider.slick("setPosition");
207 + } catch (e) {
208 + // ignore
209 + }
210 + } else {
211 + // Try immediately, then retry while the widget becomes visible.
212 + retryInit(0);
213 + }
214 +
215 + // Refresh on image load (common cause of wrong widths on frontend).
216 + $contentTickerSlider.find("img").one("load", function () {
217 + if ($contentTickerSlider.hasClass("slick-initialized")) {
218 + try {
219 + $contentTickerSlider.slick("setPosition");
220 + } catch (e) {
221 + // ignore
222 + }
223 + } else {
224 + retryInit(0);
225 + }
226 + }).each(function () {
227 + if (this.complete) {
228 + $(this).trigger("load");
229 + }
109 230 });
110 231
232 + // Also refresh on global events.
233 + $(window).on("load resize orientationchange", function () {
234 + if ($contentTickerSlider.hasClass("slick-initialized")) {
235 + try {
236 + $contentTickerSlider.slick("setPosition");
237 + } catch (e) {
238 + // ignore
239 + }
240 + } else {
241 + retryInit(0);
242 + }
243 + });
244 +
245 + document.addEventListener("visibilitychange", function () {
246 + if (!document.hidden) {
247 + if ($contentTickerSlider.hasClass("slick-initialized")) {
248 + try {
249 + $contentTickerSlider.slick("setPosition");
250 + } catch (e) {
251 + // ignore
252 + }
253 + } else {
254 + retryInit(0);
255 + }
256 + }
257 + });
258 +
111 259 // Initialize marquee
112 - $contentTickerMarquee.marquee(marqueeData);
260 + if ($contentTickerMarquee.length && marqueeData) {
261 + $contentTickerMarquee.marquee(marqueeData);
262 + }
113 263
114 264 // If marquee is hidden, remove the hidden class
115 265 if ($element.find(".king-addons-marquee-hidden").length) {
116 266 $element