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

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

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