PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.81
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.81
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 / Loop_Grid / script.js

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

365 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 var INIT_FLAG = 'kaLoopGridReady';
5
6 /**
7 * Wire one grid: load more, filters, masonry, carousel.
8 *
9 * @param {HTMLElement} grid Grid root.
10 */
11 function initGrid(grid) {
12 if (!grid || grid.dataset[INIT_FLAG] === '1') {
13 return;
14 }
15 grid.dataset[INIT_FLAG] = '1';
16
17 var filters = grid.querySelectorAll('.king-addons-loop-grid__filter');
18 Array.prototype.forEach.call(filters, function (filter) {
19 filter.addEventListener('click', function () {
20 applyFilter(grid, filter);
21 });
22 });
23
24 grid.addEventListener('click', function (event) {
25 var more = event.target.closest('.king-addons-loop-grid__load-more');
26 if (more && grid.contains(more)) {
27 if (more.disabled || more.hasAttribute('disabled')) {
28 return;
29 }
30 loadPage(grid, parseInt(grid.dataset.page || '1', 10) + 1, true);
31 return;
32 }
33
34 var link = event.target.closest('.king-addons-loop-grid__pagination a');
35 if (!link || !grid.contains(link)) {
36 return;
37 }
38 var href = link.getAttribute('href') || '';
39 var page = 1;
40 var match = href.match(/ka-loop-[^=]+=(\d+)/);
41 if (match) {
42 page = parseInt(match[1], 10);
43 } else if (link.classList.contains('next')) {
44 page = parseInt(grid.dataset.page || '1', 10) + 1;
45 } else if (link.classList.contains('prev')) {
46 page = Math.max(1, parseInt(grid.dataset.page || '1', 10) - 1);
47 }
48 event.preventDefault();
49 loadPage(grid, page, false);
50 });
51
52 layoutGrid(grid);
53 initCarousel(grid);
54 }
55
56 /**
57 * Horizontal gutter from the widget's CSS variable (px). Other units fall
58 * back to 24 so Isotope does not treat "1.5em" as 1.5px.
59 *
60 * @param {HTMLElement} grid Grid root.
61 * @return {number}
62 */
63 function readGap(grid) {
64 var raw = window.getComputedStyle(grid).getPropertyValue('--ka-loop-gap').trim();
65 var px = parseFloat(raw);
66 if (!raw || raw.indexOf('px') === -1 || isNaN(px)) {
67 return 24;
68 }
69 return px;
70 }
71
72 /**
73 * Masonry after images have loaded.
74 *
75 * @param {HTMLElement} grid Grid root.
76 */
77 function layoutGrid(grid) {
78 if (grid.dataset.layout !== 'masonry') {
79 return;
80 }
81
82 var items = grid.querySelector('.king-addons-loop-grid__items');
83 if (!items || typeof window.IsotopeKng !== 'function') {
84 return;
85 }
86
87 var run = function () {
88 if (grid._kaIso) {
89 grid._kaIso.reloadItems();
90 grid._kaIso.layout();
91 return;
92 }
93 grid._kaIso = new window.IsotopeKng(items, {
94 itemSelector: '.king-addons-loop-grid__item',
95 layoutMode: 'masonry',
96 percentPosition: true,
97 transitionDuration: '0.2s',
98 masonry: {
99 columnWidth: '.king-addons-loop-grid__sizer',
100 gutter: readGap(grid)
101 }
102 });
103 };
104
105 if (typeof window.imagesLoaded === 'function') {
106 window.imagesLoaded(items, run);
107 } else {
108 run();
109 }
110 }
111
112 /**
113 * Swiper for carousel layout.
114 *
115 * @param {HTMLElement} grid Grid root.
116 */
117 function initCarousel(grid) {
118 if (grid.dataset.layout !== 'carousel' || typeof window.Swiper !== 'function') {
119 return;
120 }
121
122 var el = grid.querySelector('.king-addons-loop-grid__swiper');
123 if (!el || el.swiper) {
124 return;
125 }
126
127 var config = {};
128 try {
129 config = JSON.parse(grid.dataset.swiper || '{}');
130 } catch (error) {
131 config = {};
132 }
133
134 var options = {
135 slidesPerView: config.slidesMobile || 1,
136 spaceBetween: config.gap || 24,
137 speed: config.speed || 400,
138 loop: !!config.loop,
139 keyboard: { enabled: true },
140 a11y: { enabled: true },
141 breakpoints: {
142 768: { slidesPerView: config.slidesTablet || 2 },
143 1025: { slidesPerView: config.slides || 3 }
144 }
145 };
146
147 if (config.autoplay) {
148 options.autoplay = { delay: config.delay || 4000, disableOnInteraction: false };
149 }
150 if (config.arrows) {
151 options.navigation = {
152 nextEl: el.querySelector('.swiper-button-next'),
153 prevEl: el.querySelector('.swiper-button-prev')
154 };
155 }
156 if (config.dots) {
157 options.pagination = {
158 el: el.querySelector('.swiper-pagination'),
159 clickable: true
160 };
161 }
162
163 grid._kaSwiper = new window.Swiper(el, options);
164 }
165
166 /**
167 * Switch the active filter and reload page 1.
168 *
169 * @param {HTMLElement} grid Grid root.
170 * @param {HTMLElement} button Filter button.
171 */
172 function applyFilter(grid, button) {
173 var next = button.getAttribute('data-filter') || '';
174 grid.dataset.filter = next;
175 grid.dataset.page = '1';
176
177 var buttons = grid.querySelectorAll('.king-addons-loop-grid__filter');
178 Array.prototype.forEach.call(buttons, function (item) {
179 var on = item === button;
180 item.classList.toggle('is-active', on);
181 item.setAttribute('aria-pressed', on ? 'true' : 'false');
182 });
183
184 var bar = grid.querySelector('.king-addons-loop-grid__filters');
185 if (bar && bar.getAttribute('data-deeplink') === '1') {
186 var key = 'ka-lf-' + (grid.dataset.elementId || '');
187 var url = new URL(window.location.href);
188 if (next) {
189 url.searchParams.set(key, next);
190 } else {
191 url.searchParams.delete(key);
192 }
193 window.history.replaceState({}, '', url.toString());
194 }
195
196 loadPage(grid, 1, false);
197 }
198
199 /**
200 * Fetch a page: append for load more, replace otherwise.
201 *
202 * @param {HTMLElement} grid Grid root.
203 * @param {number} page Page number.
204 * @param {boolean} append Load-more mode.
205 */
206 function loadPage(grid, page, append) {
207 var ajaxUrl = grid.dataset.ajaxUrl;
208 if (!ajaxUrl) {
209 return;
210 }
211
212 var button = grid.querySelector('.king-addons-loop-grid__load-more');
213 if (button) {
214 button.classList.add('king-addons-loop-grid--busy');
215 button.setAttribute('disabled', 'disabled');
216 }
217
218 var body = new URLSearchParams();
219 body.append('action', 'ka_loop_grid');
220 body.append('nonce', grid.dataset.nonce || '');
221 body.append('post_id', grid.dataset.postId || '0');
222 body.append('element_id', grid.dataset.elementId || '');
223 body.append('page', String(page));
224 body.append('context', grid.dataset.context || '{}');
225 body.append('filter', grid.dataset.filter || '');
226
227 fetch(ajaxUrl, {
228 method: 'POST',
229 credentials: 'same-origin',
230 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
231 body: body.toString()
232 })
233 .then(function (response) { return response.json(); })
234 .then(function (payload) {
235 if (!payload || !payload.success || !payload.data) {
236 release(button);
237 return;
238 }
239
240 var items = grid.querySelector('.king-addons-loop-grid__items');
241 var empty = grid.querySelector('.king-addons-loop-grid__empty');
242
243 if (payload.data.empty) {
244 if (items) {
245 items.querySelectorAll('.king-addons-loop-grid__item').forEach(function (node) {
246 node.remove();
247 });
248 }
249 if (!empty) {
250 empty = document.createElement('div');
251 empty.className = 'king-addons-loop-grid__empty';
252 grid.insertBefore(empty, items);
253 }
254 empty.textContent = payload.data.empty_text || '';
255 empty.hidden = false;
256 } else if (items && payload.data.html) {
257 if (empty) {
258 empty.hidden = true;
259 }
260 if (append) {
261 items.insertAdjacentHTML('beforeend', payload.data.html);
262 } else {
263 var sizer = items.querySelector('.king-addons-loop-grid__sizer');
264 items.querySelectorAll('.king-addons-loop-grid__item').forEach(function (node) {
265 node.remove();
266 });
267 if (sizer) {
268 sizer.insertAdjacentHTML('afterend', payload.data.html);
269 } else {
270 items.insertAdjacentHTML('beforeend', payload.data.html);
271 }
272 }
273
274 if (window.elementorFrontend && window.elementorFrontend.elementsHandler) {
275 window.jQuery(items)
276 .find('.elementor-element')
277 .each(function () {
278 window.elementorFrontend.elementsHandler.runReadyTrigger(this);
279 });
280 }
281 }
282
283 var footer = grid.querySelector('.king-addons-loop-grid__footer');
284 if (!append && footer) {
285 footer.innerHTML = payload.data.pagination || '';
286 }
287
288 grid.dataset.page = String(payload.data.page || page);
289 grid.dataset.maxPages = String(payload.data.max_pages || grid.dataset.maxPages || '1');
290
291 layoutGrid(grid);
292
293 if (button) {
294 if (parseInt(grid.dataset.page, 10) >= parseInt(grid.dataset.maxPages, 10)) {
295 finish(grid, button);
296 } else {
297 release(button);
298 }
299 }
300 })
301 .catch(function () {
302 release(button);
303 });
304 }
305
306 /**
307 * Re-enable the button.
308 *
309 * @param {HTMLElement|null} button Button.
310 */
311 function release(button) {
312 if (!button) {
313 return;
314 }
315 button.classList.remove('king-addons-loop-grid--busy');
316 button.removeAttribute('disabled');
317 }
318
319 /**
320 * Nothing left to load.
321 *
322 * @param {HTMLElement} grid Grid root.
323 * @param {HTMLElement} button Load more button.
324 */
325 function finish(grid, button) {
326 button.remove();
327 var done = grid.querySelector('.king-addons-loop-grid__all-loaded');
328 if (done) {
329 done.hidden = false;
330 }
331 }
332
333 /**
334 * Find every grid on the page.
335 *
336 * @param {ParentNode} scope Root to search.
337 */
338 function initAll(scope) {
339 var root = scope || document;
340 var grids = root.querySelectorAll('[data-ka-loop-grid]');
341 Array.prototype.forEach.call(grids, initGrid);
342 }
343
344 if (document.readyState === 'loading') {
345 document.addEventListener('DOMContentLoaded', function () {
346 initAll(document);
347 });
348 } else {
349 initAll(document);
350 }
351
352 window.addEventListener('elementor/frontend/init', function () {
353 if (!window.elementorFrontend || !window.elementorFrontend.hooks) {
354 return;
355 }
356
357 window.elementorFrontend.hooks.addAction(
358 'frontend/element_ready/king-addons-loop-grid.default',
359 function ($scope) {
360 initAll($scope && $scope[0] ? $scope[0] : document);
361 }
362 );
363 });
364 })();
365