PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.36
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.36
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 / assets / libraries / grid / media.js

media.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.36, at includes/assets/libraries/grid/media.js

1,209 lines 74.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // noinspection JSUnresolvedReference,DuplicatedCode
2
3 "use strict";
4 (function ($) {
5 $(window).on("elementor/frontend/init", () => {
6
7 const gridHooks = [
8 "frontend/element_ready/king-addons-media-grid.default"
9 ];
10
11 const gridHandler = ($scope) => {
12 elementorFrontend.elementsHandler.addHandler(
13 elementorModules.frontend.handlers.Base.extend({
14 onInit() {
15 const $body = $("body");
16 const isEditor = $body.hasClass("elementor-editor-active");
17 const $grid = this.$element.find(".king-addons-grid");
18 if (!$grid.length) return;
19
20 /* ──────────────────────────────────────
21 * UTILITY FUNCTIONS
22 * ────────────────────────────────────── */
23
24 // Simple debounce helper.
25 const debounce = (func, threshold = 100, execAsap) => {
26 let timeout;
27 return function (...args) {
28 const context = this;
29 const delayed = () => {
30 if (!execAsap) func.apply(context, args);
31 timeout = null;
32 };
33 if (timeout) clearTimeout(timeout);
34 else if (execAsap) func.apply(context, args);
35 timeout = setTimeout(delayed, threshold);
36 };
37 };
38
39 // Attach "smartresize" to jQuery.
40 $.fn.smartresize = function (fn) {
41 return fn ? this.on("resize", debounce(fn)) : this.trigger("smartresize");
42 };
43
44 // Parse grid settings.
45 const settingsData = $grid.attr("data-settings");
46 const settings = settingsData ? JSON.parse(settingsData) : false;
47
48 /* ──────────────────────────────────────
49 * INITIAL EVENT HANDLERS
50 * ────────────────────────────────────── */
51
52 // Handle WooCommerce orderby form.
53 if ($scope.find(".king-addons-grid-orderby form").length) {
54 const $orderbyForm = $scope.find(".king-addons-grid-orderby form");
55 $scope.find(".orderby").on("change", () => $orderbyForm.trigger("submit"));
56 }
57
58 // Adjust result count text if WooCommerce count element exists.
59 if (settings && $scope.find(".woocommerce-result-count").length) {
60 adjustResultCount($scope, $grid, settings, isEditor);
61 }
62
63 // Helper to schedule a delayed isotope layout.
64 const scheduleIsotopeLayout = (delay) =>
65 setTimeout(() => isotopeLayout(settings), delay);
66
67 if (settings) {
68 // Perform initial layout.
69 isotopeLayout(settings);
70 scheduleIsotopeLayout(100);
71 if (isEditor) {
72 scheduleIsotopeLayout(500);
73 scheduleIsotopeLayout(1000);
74 }
75 $(window).on("load", () => scheduleIsotopeLayout(100));
76 $(document).ready(() => scheduleIsotopeLayout(100));
77 $(window).smartresize(() => scheduleIsotopeLayout(200));
78
79 // If dynamic grid settings exist, set up filtering and “load more” experiments.
80 if (settings.grid_settings) {
81 loadMoreExperiment();
82 filtersExperiment();
83 }
84 isotopeFilters(settings);
85
86 let initialItems = 0;
87 $grid.on("arrangeComplete", (e, filteredItems) => {
88 animateGridItems(filteredItems, settings, $grid);
89 initialItems = filteredItems.length;
90 });
91
92 // Once images load, set grid opacity and equalize item heights.
93 $grid.imagesLoaded(() => {
94 if ($grid.css("opacity") !== "1") $grid.css("opacity", "1");
95 setTimeout(() => $grid.addClass("grid-images-loaded"), 500);
96 setEqualHeight(settings);
97 });
98
99 // Pagination: load-more or infinite-scroll.
100 if (["load-more", "infinite-scroll"].includes(settings.pagination_type)) {
101 if ($scope.find(".king-addons-grid-pagination").length && !isEditor) {
102 setupInfiniteScroll(settings);
103 } else {
104 $scope.find(".king-addons-load-more-btn").on("click", () =>
105 alert(
106 "Load More is Disabled in the Editor! Please Preview this Page to see it in action"
107 )
108 );
109 }
110 }
111 } else {
112 // Fallback: initialize Slick slider.
113 $grid.animate({opacity: "1"}, 1000);
114 initSlickSlider();
115 }
116
117 // Additional features.
118 if ($grid.find(".king-addons-grid-item-add-to-cart").length) {
119 setupAddToCart();
120 }
121 postSharing();
122 mediaHoverLink();
123 if (
124 !$scope.hasClass("elementor-widget-king-addons-woo-category-grid-pro") &&
125 !$scope.hasClass("elementor-widget-king-addons-category-grid-pro")
126 ) {
127 lightboxPopup(settings);
128 }
129 postLikes(settings);
130 lazyLoadObserver();
131
132 /* ──────────────────────────────────────
133 * FUNCTION DEFINITIONS
134 * ────────────────────────────────────── */
135
136 // Adjust WooCommerce result count.
137 function adjustResultCount($scope, $grid, s, isEditor) {
138 const $resultCount = $scope.find(".woocommerce-result-count");
139 let text = $resultCount.text();
140 const scopeId = $scope.data("id");
141 const storageKey = `king-addons-cached-items-length-${scopeId}`;
142 let cachedLength = localStorage.getItem(storageKey);
143 if (!cachedLength || isEditor) {
144 cachedLength = $scope.find(".king-addons-grid-item").length;
145 localStorage.setItem(storageKey, cachedLength);
146 }
147 const itemsPerPage = s.query_posts_per_page || parseInt(cachedLength, 10);
148 if (isNaN(itemsPerPage) || itemsPerPage <= 0) return;
149 let currentPage = 1;
150 const $currentPage = $scope.find(".king-addons-grid-current-page");
151 if ($currentPage.length) {
152 currentPage = parseInt($currentPage.text().trim(), 10) || 1;
153 }
154 const totalMatch = text.match(/of (\d+) results/);
155 const totalItems = totalMatch ? parseInt(totalMatch[1].trim(), 10) : itemsPerPage;
156 if (isNaN(totalItems) || totalItems <= 0) return;
157 const startItem = (currentPage - 1) * itemsPerPage + 1;
158 const endItem = Math.min(startItem + itemsPerPage - 1, totalItems);
159 text = text.replace(/\d+\u2013\d+/, `${startItem}\u2013${endItem}`);
160 $resultCount.text(text);
161 }
162
163 // Layout the grid using Isotope (or its custom wrapper).
164 function isotopeLayout(s, $response = "") {
165 const layout = s.layout;
166 const columnsDesktop = parseInt(s.columns_desktop, 10);
167 let items = $response ? $response : $grid.find(".king-addons-grid-item"),
168 contWidth = $grid.width() + s.gutter_hr - 0.3,
169 viewportWidth = $(window).outerWidth(),
170 columns,
171 gutterHr,
172 gutterVr;
173
174 // Breakpoints.
175 const {mobile, mobile_extra, tablet, tablet_extra, laptop, widescreen} =
176 elementorFrontend.config.responsive.breakpoints;
177 const activeBps = elementorFrontend.config.responsive.activeBreakpoints;
178 let cMobile = 1,
179 cMobileExtra,
180 cTablet = 2,
181 cTabletExtra,
182 cLaptop,
183 cWideScreen;
184 $scope
185 .attr("class")
186 .split(" ")
187 .forEach((cl) => {
188 if (/mobile\d/.test(cl)) cMobile = parseInt(cl.slice(-1), 10);
189 if (/mobile_extra\d/.test(cl)) cMobileExtra = parseInt(cl.slice(-1), 10);
190 if (/tablet\d/.test(cl)) cTablet = parseInt(cl.slice(-1), 10);
191 if (/tablet_extra\d/.test(cl)) cTabletExtra = parseInt(cl.slice(-1), 10);
192 if (/widescreen\d/.test(cl)) cWideScreen = parseInt(cl.slice(-1), 10);
193 if (/laptop\d/.test(cl)) cLaptop = parseInt(cl.slice(-1), 10);
194 });
195
196 if (viewportWidth <= mobile.value && activeBps.mobile) {
197 columns = cMobile;
198 gutterHr = s.gutter_hr_mobile;
199 gutterVr = s.gutter_vr_mobile;
200 } else if (viewportWidth <= mobile_extra.value && activeBps.mobile_extra) {
201 columns = cMobileExtra || cTablet;
202 gutterHr = s.gutter_hr_mobile_extra;
203 gutterVr = s.gutter_vr_mobile_extra;
204 } else if (viewportWidth <= tablet.value && activeBps.tablet) {
205 columns = cTablet;
206 gutterHr = s.gutter_hr_tablet;
207 gutterVr = s.gutter_vr_tablet;
208 } else if (viewportWidth <= tablet_extra.value && activeBps.tablet_extra) {
209 columns = cTabletExtra || cTablet;
210 gutterHr = s.gutter_hr_tablet_extra;
211 gutterVr = s.gutter_vr_tablet_extra;
212 } else if (viewportWidth <= laptop.value && activeBps.laptop) {
213 columns = cLaptop || columnsDesktop;
214 gutterHr = s.gutter_hr_laptop;
215 gutterVr = s.gutter_vr_laptop;
216 } else if (viewportWidth <= widescreen.value) {
217 columns = columnsDesktop;
218 gutterHr = s.gutter_hr;
219 gutterVr = s.gutter_vr;
220 } else {
221 columns = cWideScreen || columnsDesktop;
222 gutterHr = s.gutter_hr_widescreen;
223 gutterVr = s.gutter_vr_widescreen;
224 }
225 if (columns > 8) columns = 8;
226 items.outerWidth(Math.floor(contWidth / columns - gutterHr));
227 items.css("margin-bottom", `${gutterVr}px`);
228
229 if (layout === "list") {
230 handleListLayout(s, items);
231 }
232
233 const isoLayoutMode = layout === "list" ? "fitRows" : layout;
234 const transDuration = s.filters_animation === "default" ? 400 : 0;
235
236 $grid.isotopekng({
237 layoutMode: isoLayoutMode,
238 masonry: {gutter: gutterHr},
239 fitRows: {gutter: gutterHr},
240 transitionDuration: transDuration,
241 percentPosition: true,
242 });
243 }
244
245 // Handle "list" layout adjustments.
246 function handleListLayout(s, items) {
247 const imageHeight = items.find(".king-addons-grid-image-wrap").outerHeight();
248 items.find(".king-addons-grid-item-below-content").css("min-height", `${imageHeight}px`);
249
250 if ($body.width() < 480) {
251 items.find(".king-addons-grid-media-wrap").css({float: "none", width: "100%"});
252 items.find(".king-addons-grid-item-below-content").css({
253 float: "none",
254 width: "100%",
255 "min-height": "0",
256 });
257 } else {
258 const {media_align: align, media_width: mWidth, media_distance: mDistance} = s;
259 if (align === "zigzag") {
260 handleZigzag(items, mWidth, mDistance);
261 } else {
262 items.find(".king-addons-grid-media-wrap").css({
263 float: align,
264 width: `${mWidth}%`,
265 [`margin-${align === "left" ? "right" : "left"}`]: `${mDistance}px`,
266 });
267 items.find(".king-addons-grid-item-below-content").css({
268 float: align,
269 width: `calc((100% - ${mWidth}%) - ${mDistance}px)`,
270 });
271 }
272 }
273 }
274
275 // Alternate ("zigzag") layout for list items.
276 function handleZigzag(items, mWidth, mDistance) {
277 items.filter(":even").each(function () {
278 $(this).find(".king-addons-grid-media-wrap").css({
279 float: "left",
280 width: `${mWidth}%`,
281 "margin-right": `${mDistance}px`,
282 });
283 $(this).find(".king-addons-grid-item-below-content").css({
284 float: "left",
285 width: `calc((100% - ${mWidth}%) - ${mDistance}px)`,
286 });
287 });
288 items.filter(":odd").each(function () {
289 $(this).find(".king-addons-grid-media-wrap").css({
290 float: "right",
291 width: `${mWidth}%`,
292 "margin-left": `${mDistance}px`,
293 });
294 $(this).find(".king-addons-grid-item-below-content").css({
295 float: "right",
296 width: `calc((100% - ${mWidth}%) - ${mDistance}px)`,
297 });
298 });
299 }
300
301 // Equalize grid item heights for "fitRows" layout.
302 function setEqualHeight(s) {
303 if (s.layout === "fitRows") {
304 const $items = $grid.children("article");
305 const columns = Math.floor($grid.outerWidth() / $items.outerWidth());
306 if (columns > 1) {
307 const maxH = Math.max(...$items.map((_, el) => $(el).outerHeight()).get());
308 $items.css("height", `${maxH}px`);
309 if (s.stick_last_element_to_bottom === "yes") {
310 $scope.addClass("king-addons-grid-last-element-yes");
311 }
312 }
313 }
314 }
315
316 // Lazy-load images via an IntersectionObserver.
317 function lazyLoadObserver() {
318 setTimeout(() => {
319 const observer = new IntersectionObserver((entries) => {
320 entries.forEach((entry) => {
321 if (
322 entry.isIntersecting &&
323 entry.target.src.includes("icon-256x256")
324 ) {
325 setTimeout(() => {
326 entry.target.src =
327 entry.target.parentElement.dataset.src;
328 $(entry.target).toggleClass("king-addons-hidden-image");
329 $(window).trigger("resize");
330 }, 100);
331 }
332 });
333 });
334 $scope
335 .find(".king-addons-grid-image-wrap img:first-of-type")
336 .each(function () {
337 observer.observe(this);
338 });
339 }, 100);
340 }
341
342 // Update filter counts and set up filtering behavior.
343 function isotopeFilters(s, ev = "load") {
344 if (s.filters_count === "yes") {
345 $scope.find(".king-addons-grid-filters a, .king-addons-grid-filters span").each(function () {
346 const $el = $(this);
347 if (s.grid_settings && ev === "load") {
348 const thisTaxonomy =
349 $el.attr("data-filter") !== "*" ? $el.data("ajax-filter")[0] : "*";
350 const thisFilter =
351 $el.attr("data-filter") !== "*" ? $el.data("ajax-filter")[1] : "*";
352 $.ajax({
353 type: "POST",
354 url: KingAddonsGridData.ajaxUrl,
355 data: {
356 action: s.grid_settings
357 ? "king_addons_get_filtered_count"
358 : "king_addons_get_filtered_count",
359 king_addons_offset: 0,
360 king_addons_filter: thisFilter,
361 king_addons_taxonomy: thisTaxonomy,
362 grid_settings: s.grid_settings,
363 },
364 success: (response) => {
365 $el.find("sup").text(response.data.query_found);
366 },
367 });
368 } else {
369 if ($el.attr("data-filter") === "*") {
370 $el.find("sup").text(
371 $scope.find(".king-addons-grid-filters").next().find("article").length
372 );
373 } else {
374 $el.find("sup").text($scope.find($el.attr("data-filter")).length);
375 }
376 }
377 });
378 }
379
380 if (s.filters_linkable === "yes") return;
381
382 // Deep linking support.
383 if (s.deeplinking === "yes") {
384 let deepLink = window.location.hash.replace("#filter:", ".");
385 if (window.location.hash.match("#filter:all")) deepLink = "*";
386 const activeFilter = $scope
387 .find(`.king-addons-grid-filters span[data-filter="${deepLink}"]`)
388 .not(".king-addons-back-filter");
389 $scope.find(".king-addons-grid-filters span").removeClass("king-addons-active-filter");
390 activeFilter.addClass("king-addons-active-filter");
391 $grid.isotopekng({filter: deepLink});
392 s.lightbox.selector =
393 deepLink === "*" ? ".king-addons-grid-image-wrap" : `${deepLink} .king-addons-grid-image-wrap`;
394 lightboxPopup(s);
395 }
396
397 // Hide empty filters.
398 if (s.filters_hide_empty === "yes" && !s.grid_settings) {
399 $scope.find(".king-addons-grid-filters span").each(function () {
400 const filterClass = $(this).attr("data-filter");
401 if (filterClass !== "*" && $grid.find(filterClass).length === 0) {
402 $(this).parent("li").addClass("king-addons-hidden-element");
403 } else {
404 $(this).parent("li").removeClass("king-addons-hidden-element");
405 }
406 });
407 }
408
409 // Default filter.
410 if (
411 !$scope.hasClass("elementor-widget-king-addons-woo-category-grid-pro") &&
412 !$scope.hasClass("elementor-widget-king-addons-category-grid-pro") &&
413 s.filters_default_filter
414 ) {
415 setTimeout(() => {
416 const filterEl = $scope
417 .find(".king-addons-grid-filters")
418 .find(`span[data-filter*="-${s.filters_default_filter}"]`);
419 if (filterEl.length) filterEl[0].click();
420 }, 100);
421 }
422
423 // Filter click behavior.
424 if (!s.grid_settings) {
425 $scope.find(".king-addons-grid-filters span").on("click", function () {
426 const filterClass = $(this).data("filter");
427 $scope.find(".king-addons-grid-filters span").removeClass("king-addons-active-filter");
428 $(this).addClass("king-addons-active-filter");
429 if (s.deeplinking === "yes") {
430 const filterHash =
431 filterClass === "*" ? "#filter:all" : `#filter:${filterClass.replace(".", "")}`;
432 window.location.href =
433 window.location.pathname + window.location.search + filterHash;
434 }
435 if (["infinite-scroll", "load-more"].includes(s.pagination_type)) {
436 if ($grid.find($(this).attr("data-filter")).length === 0) {
437 $grid.infiniteScroll("loadNextPage");
438 }
439 }
440 if (s.filters_animation !== "default") {
441 $scope.find(".king-addons-grid-item-inner").css({
442 opacity: "0",
443 transition: "none",
444 });
445 if (s.filters_animation === "fade-slide") {
446 $scope.find(".king-addons-grid-item-inner").css("top", "20px");
447 } else if (s.filters_animation === "zoom") {
448 $scope.find(".king-addons-grid-item-inner").css("transform", "scale(0.01)");
449 }
450 }
451 $grid.isotopekng({filter: filterClass});
452 s.lightbox.selector =
453 filterClass === "*" ? ".king-addons-grid-image-wrap" : `${filterClass} .king-addons-grid-image-wrap`;
454 $grid.data("lightGallery").destroy(true);
455 $grid.lightGallery(s.lightbox);
456 });
457 }
458 }
459
460 // Experiment: dynamic filtering via AJAX.
461 function filtersExperiment() {
462 const countAction = $scope.hasClass("elementor-widget-king-addons-woo-grid")
463 ? "king_addons_get_woocommerce_filtered_count"
464 : "king_addons_get_filtered_count";
465 const contentAction = $scope.hasClass("elementor-widget-king-addons-woo-grid")
466 ? "king_addons_filter_woocommerce_products"
467 : "king_addons_filter_grid_posts";
468
469 $scope.find(".king-addons-grid-filters").on("click", "span", function (e) {
470 e.preventDefault();
471 e.stopPropagation();
472 // e.stopImmediatePropagation();
473
474 const filterClass = $(this).data("filter");
475 const thisTaxonomy = filterClass !== "*" ? $(this).data("ajax-filter")[0] : "*";
476 const thisFilter = filterClass !== "*" ? $(this).data("ajax-filter")[1] : "*";
477 const loader = `<div class="king-addons-grid-loader-wrap"><div class="king-addons-ring"><div></div><div></div><div></div><div></div></div></div>`;
478
479 $scope.find(".king-addons-grid-filters span").removeClass("king-addons-active-filter");
480 $(this).addClass("king-addons-active-filter");
481
482 $grid.isotopekng("destroy");
483 $grid.html(loader);
484
485 $.ajax({
486 type: "POST",
487 url: KingAddonsGridData.ajaxUrl,
488 data: {
489 action: countAction,
490 king_addons_offset:
491 +settings.grid_settings.query_offset +
492 $scope.find(".king-addons-grid-item").length,
493 king_addons_filter: thisFilter,
494 king_addons_taxonomy: thisTaxonomy,
495 grid_settings: settings.grid_settings,
496 },
497 success: function () {
498 $.ajax({
499 type: "POST",
500 url: KingAddonsGridData.ajaxUrl,
501 data: {
502 action: contentAction,
503 king_addons_item_length:
504 +settings.grid_settings.query_offset +
505 $scope.find(".king-addons-grid-item").length,
506 king_addons_filter: thisFilter,
507 king_addons_taxonomy: thisTaxonomy,
508 grid_settings: settings.grid_settings,
509 },
510 success: function (resp) {
511 setTimeout(() => {
512 $grid.addClass("king-addons-zero-opacity");
513 $grid.html($(resp));
514 isotopeLayout(settings, $(resp));
515 setTimeout(() => {
516 isotopeLayout(settings);
517 window.dispatchEvent(new Event("resize"));
518 window.dispatchEvent(new Event("scroll"));
519 }, 500);
520 mediaHoverLink();
521 $grid.removeClass("king-addons-zero-opacity");
522 }, 800);
523 },
524 });
525 },
526 });
527 });
528 }
529
530 // Experiment: load-more via AJAX.
531 function loadMoreExperiment() {
532 const countAction = $scope.hasClass("elementor-widget-king-addons-woo-grid")
533 ? "king_addons_get_woocommerce_filtered_count"
534 : "king_addons_get_filtered_count";
535 const contentAction = $scope.hasClass("elementor-widget-king-addons-woo-grid")
536 ? "king_addons_filter_woocommerce_products"
537 : "king_addons_filter_grid_posts";
538 const $pagination = $scope.find(".king-addons-grid-pagination");
539
540 $scope.find(".king-addons-load-more-btn").on("click", function (e) {
541 e.preventDefault();
542 e.stopPropagation();
543 // e.stopImmediatePropagation();
544
545 let thisTaxonomy = "*";
546 let thisFilter = "*";
547 const $activeFilter = $scope.find(".king-addons-active-filter");
548 if ($activeFilter.length && $activeFilter.data("filter") !== "*") {
549 thisTaxonomy = $activeFilter.data("ajax-filter")[0];
550 thisFilter = $activeFilter.data("ajax-filter")[1];
551 }
552
553 $pagination.find(".king-addons-load-more-btn").hide();
554 $pagination.find(".king-addons-pagination-loading").css("display", "inline-block");
555
556 $.ajax({
557 type: "POST",
558 url: KingAddonsGridData.ajaxUrl,
559 data: {
560 action: countAction,
561 king_addons_offset:
562 +settings.grid_settings.query_offset +
563 $grid.find(".king-addons-grid-item").length,
564 king_addons_filter: thisFilter,
565 king_addons_taxonomy: thisTaxonomy,
566 grid_settings: settings.grid_settings,
567 },
568 success: function (res) {
569 $.ajax({
570 type: "POST",
571 url: KingAddonsGridData.ajaxUrl,
572 data: {
573 action: contentAction,
574 king_addons_offset:
575 +settings.grid_settings.query_offset +
576 $grid.find(".king-addons-grid-item").length,
577 king_addons_filter: thisFilter,
578 king_addons_taxonomy: thisTaxonomy,
579 grid_settings: settings.grid_settings,
580 },
581 success: function (resp) {
582 const $items = $(resp);
583 $grid.infiniteScroll("appendItems", $items);
584 $grid.isotopekng("appended", $items);
585 $items.imagesLoaded().progress(() => {
586 isotopeLayout(settings);
587 setTimeout(() => isotopeLayout(settings), 100);
588 setTimeout(() => $grid.addClass("grid-images-loaded"), 500);
589 });
590 $pagination.find(".king-addons-pagination-loading").hide();
591 if (res.data.page_count > 1) {
592 $pagination.find(".king-addons-load-more-btn").fadeIn();
593 } else {
594 $pagination.find(".king-addons-pagination-finish").fadeIn(1000);
595 $pagination.delay(2000).fadeOut(1000);
596 setTimeout(() => $pagination.find(".king-addons-pagination-loading").hide(), 500);
597 }
598 lightboxPopup(settings);
599 $grid.data("lightGallery").destroy(true);
600 $grid.lightGallery(settings.lightbox);
601 mediaHoverLink();
602 postSharing();
603 lazyLoadObserver();
604 window.dispatchEvent(new Event("resize"));
605 window.dispatchEvent(new Event("scroll"));
606 },
607 });
608 },
609 });
610 });
611 }
612
613 // Setup Infinite Scroll.
614 function setupInfiniteScroll(s) {
615 const $pagination = $scope.find(".king-addons-grid-pagination");
616 const scopeClass = `.elementor-element-${$scope.attr("data-id")}`;
617 let navClass = false,
618 threshold = false;
619 if (s.pagination_type === "infinite-scroll") {
620 threshold = 300;
621 navClass = `${scopeClass} .king-addons-load-more-btn`;
622 }
623 $grid.infiniteScroll({
624 path: `${scopeClass} .king-addons-grid-pagination a`,
625 hideNav: navClass,
626 append: false,
627 history: false,
628 scrollThreshold: threshold,
629 status: `${scopeClass} .page-load-status`,
630 onInit() {
631 this.on("load", () => $grid.removeClass("grid-images-loaded"));
632 },
633 });
634 $grid.on("request.infiniteScroll", () => {
635 $pagination.find(".king-addons-load-more-btn").hide();
636 $pagination.find(".king-addons-pagination-loading").css("display", "inline-block");
637 });
638 let pagesLoaded = 0;
639 $grid.on("load.infiniteScroll", (event, response) => {
640 pagesLoaded++;
641 const $items = $(response).find(scopeClass).find(".king-addons-grid-item");
642 if ($scope.find(".woocommerce-result-count").length) {
643 let updatedCount = $scope.find(".woocommerce-result-count").text();
644 updatedCount = updatedCount.replace(
645 /\d\u2013\d+/,
646 `1–${$scope.find(".king-addons-grid-item").length + $items.length}`
647 );
648 $scope.find(".woocommerce-result-count").text(updatedCount);
649 }
650 $grid.infiniteScroll("appendItems", $items);
651 $grid.isotopekng("appended", $items);
652 $items.imagesLoaded().progress(() => {
653 isotopeLayout(s);
654 setTimeout(() => {
655 isotopeLayout(s);
656 isotopeFilters(s);
657 }, 10);
658 setTimeout(() => $grid.addClass("grid-images-loaded"), 500);
659 });
660 $pagination.find(".king-addons-pagination-loading").hide();
661 if (pagesLoaded < s.pagination_max_pages) {
662 if (s.pagination_type === "load-more") {
663 $pagination.find(".king-addons-load-more-btn").fadeIn();
664 if ($scope.find(".king-addons-grid-filters").length) {
665 const activeF = $scope.find(".king-addons-active-filter");
666 if (activeF.length && activeF.attr("data-filter") !== "*") {
667 const filterClass = activeF.attr("data-filter").slice(1);
668 let foundOne = false;
669 $items.each(function () {
670 if ($(this).hasClass(filterClass)) {
671 foundOne = true;
672 return false;
673 }
674 });
675 if (!foundOne) $grid.infiniteScroll("loadNextPage");
676 }
677 }
678 }
679 } else {
680 $pagination.find(".king-addons-pagination-finish").fadeIn(1000);
681 $pagination.delay(2000).fadeOut(1000);
682 setTimeout(() => $pagination.find(".king-addons-pagination-loading").hide(), 500);
683 }
684 lightboxPopup(s);
685 $grid.data("lightGallery").destroy(true);
686 $grid.lightGallery(s.lightbox);
687 mediaHoverLink();
688 postSharing();
689 lazyLoadObserver();
690 setTimeout(() => {
691 setEqualHeight(s);
692 window.dispatchEvent(new Event("resize"));
693 }, 500);
694 });
695 $pagination.find(".king-addons-load-more-btn").on("click", () => {
696 $grid.infiniteScroll("loadNextPage");
697 return false;
698 });
699 }
700
701 // Initialize the Slick slider.
702 function initSlickSlider() {
703 const settingsSlick = JSON.parse($grid.attr("data-slick") || "{}");
704 $grid.slick({
705 appendDots: $scope.find(".king-addons-grid-slider-dots"),
706 rows: settingsSlick.sliderRows,
707 customPaging: () => `<span class="king-addons-grid-slider-dot"></span>`,
708 slidesToShow: getSliderColumns("desktop"),
709 responsive: getSliderResponsiveOptions(settingsSlick),
710 });
711 handleSlickArrows();
712 handleSlickDots();
713 }
714
715 // Get the number of slider columns.
716 function getSliderColumns(type) {
717 const match = $scope.attr("class").match(/king-addons-grid-slider-columns-(\d)/);
718 return type === "desktop" ? (match ? parseInt(match[1], 10) : 2) : 2;
719 }
720
721 // Get responsive slider options.
722 function getSliderResponsiveOptions(sl) {
723 const className = $scope.attr("class");
724 const colDesktop = getSliderColumns("desktop");
725 const colWide = extractColumns(className, "widescreen") || colDesktop;
726 const colLaptop = extractColumns(className, "laptop") || colDesktop;
727 const colTablet = extractColumns(className, "tablet") || 2;
728 const colTabletExtra = extractColumns(className, "tablet_extra") || colTablet;
729 const colMobileExtra = extractColumns(className, "mobile_extra") || colTablet;
730 const colMobile = extractColumns(className, "mobile") || 1;
731 const slidesToScroll = sl.sliderSlidesToScroll;
732 const adjust = (cols) => (slidesToScroll > cols ? 1 : slidesToScroll);
733 return [
734 {breakpoint: 10000, settings: {slidesToShow: colWide, slidesToScroll: adjust(colWide)}},
735 {
736 breakpoint: 2399,
737 settings: {slidesToShow: colDesktop, slidesToScroll: adjust(colDesktop)}
738 },
739 {
740 breakpoint: 1221,
741 settings: {slidesToShow: colLaptop, slidesToScroll: adjust(colLaptop)}
742 },
743 {
744 breakpoint: 1200,
745 settings: {slidesToShow: colTabletExtra, slidesToScroll: adjust(colTabletExtra)}
746 },
747 {
748 breakpoint: 1024,
749 settings: {slidesToShow: colTablet, slidesToScroll: adjust(colTablet)}
750 },
751 {
752 breakpoint: 880,
753 settings: {slidesToShow: colMobileExtra, slidesToScroll: adjust(colMobileExtra)}
754 },
755 {
756 breakpoint: 768,
757 settings: {slidesToShow: colMobile, slidesToScroll: adjust(colMobile)}
758 },
759 ];
760 }
761
762 // Extract a number of columns from a class name.
763 function extractColumns(className, type) {
764 const match = className.match(new RegExp(`columns--${type}(\\d)`));
765 return match ? parseInt(match[1], 10) : false;
766 }
767
768 // Adjust the slider arrows based on available space.
769 function handleSlickArrows() {
770 const $prevArrow = $scope.find(".king-addons-grid-slider-prev-arrow");
771 const $nextArrow = $scope.find(".king-addons-grid-slider-next-arrow");
772 if (!$prevArrow.length || !$nextArrow.length) return;
773 const positionSum = $prevArrow.position().left * -2;
774 $(window).on("load", checkArrows);
775 $(window).smartresize(checkArrows);
776
777 function checkArrows() {
778 if (
779 $(window).width() <=
780 $scope.outerWidth() +
781 $prevArrow.outerWidth() +
782 $nextArrow.outerWidth() +
783 positionSum
784 ) {
785 $prevArrow.addClass("king-addons-adjust-slider-prev-arrow");
786 $nextArrow.addClass("king-addons-adjust-slider-next-arrow");
787 } else {
788 $prevArrow.removeClass("king-addons-adjust-slider-prev-arrow");
789 $nextArrow.removeClass("king-addons-adjust-slider-next-arrow");
790 }
791 }
792 }
793
794 // Adjust slider dots if needed.
795 function handleSlickDots() {
796 if (
797 $scope.find(".slick-dots").length &&
798 $scope.hasClass("king-addons-grid-slider-dots-horizontal")
799 ) {
800 resizeDots();
801 $(window).smartresize(() => setTimeout(resizeDots, 300));
802 }
803
804 function resizeDots() {
805 const $dots = $scope.find(".slick-dots li");
806 const marginRight = parseInt($dots.find("span").css("margin-right"), 10);
807 const width = $dots.outerWidth() * $dots.length - marginRight;
808 $scope.find(".slick-dots").css("width", width);
809 }
810 }
811
812 // Setup "Add to Cart" behavior.
813 function setupAddToCart() {
814 const $addCartIcon = $grid.find(".king-addons-grid-item-add-to-cart i");
815 let addCartIconClass = $addCartIcon.attr("class") || "";
816 if (addCartIconClass) {
817 addCartIconClass = addCartIconClass.substring(
818 addCartIconClass.indexOf("fa-")
819 );
820 }
821 $body.on("adding_to_cart", (ev, btn) => btn.fadeTo("slow", 0));
822 $body.on("added_to_cart", (ev, fragments, hash, btn) => {
823 const productId = btn.data("product_id");
824 btn.next().fadeTo(700, 1).css("display", "inline-block");
825 btn.css("display", "none");
826 if (btn.data("atc-popup") === "sidebar") {
827 $(".king-addons-mini-cart-toggle-wrap a").each(function () {
828 const $miniCart = $(this)
829 .closest(".king-addons-mini-cart-inner")
830 .find(".king-addons-mini-cart");
831 if ($miniCart.css("display") === "none") $(this).trigger("click");
832 });
833 } else if (btn.data("atc-popup") === "popup") {
834 addToCartPopup(btn, productId);
835 }
836 if (addCartIconClass) {
837 btn.find("i").removeClass(addCartIconClass).addClass("fa-check");
838 setTimeout(() => {
839 btn.find("i").removeClass("fa-check").addClass(addCartIconClass);
840 }, 3500);
841 }
842 });
843
844 function addToCartPopup(btn, productId) {
845 const $popupItem = btn.closest(".king-addons-grid-item");
846 const popupText = $popupItem.find(".king-addons-grid-item-title").text();
847 const popupLink = btn.next().attr("href");
848 const popupImageSrc = $popupItem.find(".king-addons-grid-image-wrap").data("src");
849 const popupAnimation = btn.data("atc-animation");
850 const fadeOutIn = btn.data("atc-fade-out-in");
851 const animTime = btn.data("atc-animation-time");
852 let animationClass = "king-addons-added-to-cart-default",
853 removeAnimationClass = "king-addons-added-to-cart-popup-hide";
854 const popupImage = popupImageSrc
855 ? `<div class="king-addons-added-tc-popup-img"><img src="${popupImageSrc}" alt="" /></div>`
856 : "";
857 switch (popupAnimation) {
858 case "slide-left":
859 animationClass = "king-addons-added-to-cart-slide-in-left";
860 removeAnimationClass = "king-addons-added-to-cart-slide-out-left";
861 break;
862 case "scale-up":
863 animationClass = "king-addons-added-to-cart-scale-up";
864 removeAnimationClass = "king-addons-added-to-cart-scale-down";
865 break;
866 case "skew":
867 animationClass = "king-addons-added-to-cart-skew";
868 removeAnimationClass = "king-addons-added-to-cart-skew-off";
869 break;
870 case "fade":
871 animationClass = "king-addons-added-to-cart-fade";
872 removeAnimationClass = "king-addons-added-to-cart-fade-out";
873 break;
874 }
875 if (!$scope.find(`#king-addons-added-to-cart-${productId}`).length) {
876 $scope
877 .find(".king-addons-grid")
878 .append(
879 `<div id="king-addons-added-to-cart-${productId}" class="king-addons-added-to-cart-popup ${animationClass}">
880 ${popupImage}
881 <div class="king-addons-added-tc-title">
882 <p>${popupText} ${KingAddonsGridData.addedToCartText}</p>
883 <p><a href="${popupLink}">${KingAddonsGridData.viewCart}</a></p>
884 </div>
885 </div>`
886 );
887 setTimeout(() => {
888 $scope
889 .find(`#king-addons-added-to-cart-${productId}`)
890 .addClass(removeAnimationClass);
891 setTimeout(() => {
892 $scope.find(`#king-addons-added-to-cart-${productId}`).remove();
893 }, animTime * 1000);
894 }, fadeOutIn * 1000);
895 }
896 }
897 }
898
899 // Setup post sharing behavior.
900 function postSharing() {
901 if (!$scope.find(".king-addons-sharing-trigger").length) return;
902 const $sharingTrigger = $scope.find(".king-addons-sharing-trigger");
903 const $sharingInner = $scope.find(".king-addons-post-sharing-inner");
904 let sharingWidth = 5;
905 $sharingInner.first().find("a").each(function () {
906 sharingWidth += $(this).outerWidth() + parseInt($(this).css("margin-right"), 10);
907 });
908 const direction = $sharingTrigger.attr("data-direction");
909 if (direction === "left" || direction === "right") {
910 $sharingInner.css("width", `${sharingWidth}px`);
911 if (direction === "left") {
912 $sharingInner.css(
913 "left",
914 -(parseInt($sharingInner.find("a").css("margin-right"), 10) + sharingWidth) + "px"
915 );
916 } else {
917 $sharingInner.css({left: $sharingTrigger.css("margin-right")});
918 }
919 } else if (direction === "top") {
920 const margin = parseInt($sharingInner.find("a").css("margin-right"), 10);
921 $sharingInner.find("a").css({"margin-right": "0", "margin-top": `${margin}px`});
922 $sharingInner.css({
923 top: `-${margin}px`,
924 left: "50%",
925 transform: "translate(-50%, -100%)",
926 });
927 } else if (direction === "bottom") {
928 const margin = parseInt($sharingInner.find("a").css("margin-right"), 10);
929 $sharingInner.find("a").css({"margin-right": "0", "margin-bottom": `${margin}px`});
930 $sharingInner.css({
931 bottom: `-${margin}px`,
932 left: "50%",
933 transform: "translate(-50%, 100%)",
934 });
935 }
936 if ($sharingTrigger.attr("data-action") === "click") {
937 $sharingTrigger.on("click", function () {
938 const $inner = $(this).next();
939 if ($inner.css("visibility") === "hidden") {
940 $inner.css("visibility", "visible").find("a").css({opacity: "1", top: "0"});
941 setTimeout(() => $inner.find("a").addClass("king-addons-no-transition-delay"), $inner.find("a").length * 100);
942 } else {
943 $inner.find("a").removeClass("king-addons-no-transition-delay").css({
944 opacity: "0",
945 top: "-5px",
946 });
947 setTimeout(() => $inner.css("visibility", "hidden"), $inner.find("a").length * 100);
948 }
949 });
950 } else {
951 $sharingTrigger.on("mouseenter", function () {
952 const $inner = $(this).next();
953 $inner.css("visibility", "visible").find("a").css({opacity: "1", top: "0"});
954 setTimeout(() => $inner.find("a").addClass("king-addons-no-transition-delay"), $inner.find("a").length * 100);
955 });
956 $scope.find(".king-addons-grid-item-sharing").on("mouseleave", function () {
957 const $inner = $(this).find(".king-addons-post-sharing-inner");
958 $inner.find("a").removeClass("king-addons-no-transition-delay").css({
959 opacity: "0",
960 top: "-5px",
961 });
962 setTimeout(() => $inner.css("visibility", "hidden"), $inner.find("a").length * 100);
963 });
964 }
965 }
966
967 // Setup media hover behavior and overlay clickable links.
968 function mediaHoverLink() {
969 const $wrap = $grid.find(".king-addons-grid-image-wrap");
970 if ($wrap.data("img-on-hover") === "yes") {
971 $grid.find(".king-addons-grid-media-wrap").hover(
972 function () {
973 const $secondImg = $(this).find("img:nth-of-type(2)");
974 if ($secondImg.attr("src")) {
975 $(this).find("img:first-of-type").addClass("king-addons-hidden-img");
976 $secondImg.removeClass("king-addons-hidden-img");
977 }
978 },
979 function () {
980 const $secondImg = $(this).find("img:nth-of-type(2)");
981 if ($secondImg.attr("src")) {
982 $secondImg.addClass("king-addons-hidden-img");
983 $(this).find("img:first-of-type").removeClass("king-addons-hidden-img");
984 }
985 }
986 );
987 }
988 if ($wrap.attr("data-overlay-link") === "yes" && !isEditor) {
989 $wrap.css("cursor", "pointer").on("click", function (e) {
990 const cn = e.target.className;
991 if (
992 cn.indexOf("inner-block") !== -1 ||
993 cn.indexOf("king-addons-cv-inner") !== -1 ||
994 cn.indexOf("king-addons-grid-media-hover") !== -1
995 ) {
996 e.preventDefault();
997 let itemUrl = $(this)
998 .find(".king-addons-grid-media-hover-bg")
999 .attr("data-url")
1000 .replace("#new_tab", "");
1001 if ($grid.find(".king-addons-grid-item-title a").attr("target") === "_blank") {
1002 window.open(itemUrl, "_blank").focus();
1003 } else {
1004 window.location.href = itemUrl;
1005 }
1006 }
1007 });
1008 }
1009 }
1010
1011 function lightboxPopup(settings) {
1012 // If there are no .king-addons-grid-item-lightbox elements, exit early
1013 if (!$scope.find('.king-addons-grid-item-lightbox').length) return;
1014
1015 const lightboxElements = $scope.find('.king-addons-grid-item-lightbox');
1016 const firstOverlay = lightboxElements.find('.king-addons-grid-lightbox-overlay').first();
1017
1018 // Assign data-src and data-iframe for items not marked with .lg-initialized
1019 lightboxElements.each(function () {
1020 const el = jQuery(this);
1021 const srcAttr = el.find('.inner-block > span').attr('data-src');
1022 const article = el.closest('article').not('.slick-cloned');
1023
1024 // If not in Elementor editor mode, add data-src
1025 if (!isEditor) {
1026 article.find('.king-addons-grid-image-wrap').attr('data-src', srcAttr);
1027 }
1028
1029 // Check if it should be an iframe (not hosted in wp-content)
1030 const finalSrc = article.find('.king-addons-grid-image-wrap').attr('data-src');
1031 if (finalSrc && finalSrc.indexOf('wp-content') === -1) {
1032 article.find('.king-addons-grid-image-wrap').attr('data-iframe', 'true');
1033 }
1034
1035 // Mark article as initialized
1036 article.addClass('lg-initialized');
1037 });
1038
1039 // Initialize or re-initialize lightGallery
1040 if (!$grid.data('lightGallery')) {
1041 $grid.lightGallery(settings.lightbox);
1042 } else {
1043 $grid.data('lightGallery').destroy(true);
1044 $grid.lightGallery(settings.lightbox);
1045 }
1046
1047 // Rewrite thumbnails only once after opening the lightbox
1048 let thumbsRewritten = false;
1049 $grid.on('onAfterOpen.lg', function () {
1050 if (thumbsRewritten) return;
1051 thumbsRewritten = true;
1052
1053 jQuery('.lg-outer').find('.lg-thumb-item').each(function () {
1054 const img = jQuery(this).find('img');
1055 const original = img.attr('src');
1056 const extIndex = original.lastIndexOf('.');
1057 const dashIndex = original.lastIndexOf('-');
1058 const dashChunk = original.substring(dashIndex, extIndex);
1059
1060 // If it looks like a typical WordPress crop (e.g., -150x150), replace it
1061 if (/\d{3,}x\d{3,}/.test(dashChunk)) {
1062 img.attr('src', original.replace(dashChunk, '-150x150'));
1063 } else {
1064 // Otherwise, just insert -150x150 before the extension
1065 img.attr('src', [
1066 original.slice(0, extIndex),
1067 '-150x150',
1068 original.slice(extIndex)
1069 ].join(''));
1070 }
1071 });
1072 });
1073
1074 // Toggle certain controls on slide events
1075 $scope.find('.king-addons-grid').on('onAfterAppendSlide.lg onAfterSlide.lg', function () {
1076 const controls = jQuery('#lg-actual-size, #lg-zoom-in, #lg-zoom-out, #lg-download');
1077 const dl = jQuery('#lg-download');
1078 const dlHref = dl.attr('href');
1079
1080 // Hide or show controls based on file location
1081 if (dl.length) {
1082 if (dlHref.indexOf('wp-content') === -1) {
1083 controls.addClass('king-addons-hidden-element');
1084 } else {
1085 controls.removeClass('king-addons-hidden-element');
1086 }
1087 }
1088
1089 // If autoplay is disabled, hide the autoplay button
1090 if (settings.lightbox.autoplay === '') {
1091 jQuery('.lg-autoplay-button').css({
1092 width: 0,
1093 height: 0,
1094 overflow: 'hidden'
1095 });
1096 }
1097 });
1098
1099 // If overlay exists, move it and set click handler
1100 if (firstOverlay.length) {
1101 $scope.find('.king-addons-grid-media-hover-bg').after(firstOverlay.remove());
1102 $scope.find('.king-addons-grid-lightbox-overlay').on('click', function () {
1103 if (!isEditor) {
1104 jQuery(this).closest('article').find('.king-addons-grid-image-wrap').trigger('click');
1105 } else {
1106 alert('Lightbox is Disabled in the Editor! Please Preview this Page to see it in action.');
1107 }
1108 });
1109 } else {
1110 // Otherwise, set click on .inner-block > span
1111 lightboxElements.find('.inner-block > span').on('click', function () {
1112 if (!isEditor) {
1113 jQuery(this).closest('article').find('.king-addons-grid-image-wrap').trigger('click');
1114 } else {
1115 alert('Lightbox is Disabled in the Editor! Please Preview this Page to see it in action.');
1116 }
1117 });
1118 }
1119 }
1120
1121
1122 // Handle post likes.
1123 function postLikes() {
1124 if (!$scope.find(".king-addons-post-like-button").length) return;
1125 $scope.on("click", ".king-addons-post-like-button", function (e) {
1126 e.preventDefault();
1127 const $btn = $(this);
1128 if (!$btn.attr("data-post-id")) return false;
1129 $.ajax({
1130 type: "POST",
1131 url: $btn.attr("data-ajax"),
1132 data: {
1133 action: "king_addons_likes_init",
1134 post_id: $btn.attr("data-post-id"),
1135 nonce: $btn.attr("data-nonce"),
1136 },
1137 beforeSend: () => $btn.fadeTo(500, 0.5),
1138 success: function (response) {
1139 let iconClass = $btn.attr("data-icon");
1140 let countHTML = response.count;
1141 if (!countHTML.replace(/<\/?[^>]+(>|$)/g, "")) {
1142 countHTML = `<span class="king-addons-post-like-count">${$btn.attr("data-text")}</span>`;
1143 $btn.addClass("king-addons-likes-zero");
1144 } else {
1145 $btn.removeClass("king-addons-likes-zero");
1146 }
1147 if ($btn.hasClass("king-addons-already-liked")) {
1148 $btn.prop("title", "Like").removeClass("king-addons-already-liked");
1149 $btn.html(`<i class="${iconClass.replace("fas", "far")}"></i>${countHTML}`);
1150 } else {
1151 $btn.prop("title", "Unlike").addClass("king-addons-already-liked");
1152 $btn.html(`<i class="${iconClass.replace("far", "fas")}"></i>${countHTML}`);
1153 }
1154 $btn.fadeTo(500, 1);
1155 },
1156 });
1157 return false;
1158 });
1159 }
1160
1161 // Animate grid items after layout.
1162 function animateGridItems(filteredItems, s, $grid) {
1163 let initStager = 0,
1164 filterStager = 0,
1165 deepLinkStager = 0;
1166 if (!$grid.hasClass("grid-images-loaded")) $grid.css("opacity", "1");
1167 filteredItems.forEach((item) => {
1168 initStager += s.animation_delay;
1169 $(item.element)
1170 .find(".king-addons-grid-item-inner")
1171 .css({
1172 opacity: "1",
1173 top: "0",
1174 transform: "scale(1)",
1175 transition: `all ${s.animation_duration}s ease-in ${initStager}s`,
1176 });
1177 filterStager += s.filters_animation_delay;
1178 if ($grid.hasClass("grid-images-loaded")) {
1179 $(item.element)
1180 .find(".king-addons-grid-item-inner")
1181 .css({
1182 transition: `all ${s.filters_animation_duration}s ease-in ${filterStager}s`,
1183 });
1184 }
1185 let deepLink = window.location.hash;
1186 if (deepLink.includes("#filter:") && !deepLink.includes("#filter:*")) {
1187 deepLink = deepLink.replace("#filter:", "");
1188 if ($(item.element).hasClass(deepLink)) {
1189 deepLinkStager += s.filters_animation_delay;
1190 $(item.element)
1191 .find(".king-addons-grid-item-inner")
1192 .css({"transition-delay": `${deepLinkStager}s`});
1193 }
1194 }
1195 });
1196 }
1197 },
1198 }),
1199 {$element: $scope}
1200 );
1201 }
1202
1203 gridHooks.forEach((hook) => {
1204 elementorFrontend.hooks.addAction(hook, gridHandler);
1205 });
1206
1207 });
1208 })(jQuery);
1209