PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.0.39
Post Grid Gutenberg Blocks – PostX v5.0.39
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
ultimate-post / assets / js / ultp-infinite-scroll.js

ultp-infinite-scroll.js in Post Grid Gutenberg Blocks – PostX 5.0.39, at assets/js/ultp-infinite-scroll.js

231 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function ($) {
2 ("use strict");
3 $.fn.UltpInfiniteScroll = async function (
4 block, // Current Block
5 setSession, // set Unique Post Id
6 getUltpNonce, // Get Nonce
7 paginationAjaxCall, // Pagination API Call Function
8 ) {
9 const ultpNonce = await getUltpNonce();
10
11 const wrap = block.find(".ultp-block-wrapper");
12 const exclude = wrap.data("expost");
13 const builder = wrap.data("builder");
14 const blockid = wrap.attr("data-blockid");
15 const blockName = wrap.data("blockname");
16 const filterType = wrap.attr("data-filter_type") || "";
17
18 let filterValue = [];
19
20 // pageNum starts at 2 — page 1 is already rendered
21 let pageNum = 2;
22 let noMoreData = false;
23 let isLoading = false; // <-- ADD THIS
24
25 // Post Id
26 let post_ID =
27 block.parents(".ultp-shortcode").length !== 0 &&
28 wrap.data("selfpostid") === "no"
29 ? block.parents(".ultp-shortcode").data("postid")
30 : wrap.data("postid");
31
32 if (block.find(".ultp-builder-content").length > 0) {
33 post_ID = block.find(".ultp-builder-content").data("postid");
34 }
35
36 // Widget Block ID
37 let widgetBlockId = "";
38 const widgetBlock = block.parents(".widget_block:first");
39 if (widgetBlock.length > 0) {
40 const widget_items = widgetBlock.attr("id").split("-");
41 widgetBlockId = widget_items[widget_items.length - 1];
42 }
43
44 // Unique Post
45 const ultpCurrentUniquePosts = JSON.stringify(
46 wrap.find(".ultp-current-unique-posts").data("current-unique-posts"),
47 );
48
49 // Window Scroll
50 let scrollTimer = null;
51 function onScroll() {
52 if (scrollTimer) return;
53 scrollTimer = setTimeout(function () {
54 scrollTimer = null;
55 if (isEndReached() && !noMoreData) {
56 loadContent();
57 }
58 }, 150);
59 }
60
61 // Remove any previous handler for this block before adding a new one
62 $(window).off("scroll.ultp-iscroll-" + blockid);
63 $(window).on("scroll.ultp-iscroll-" + blockid, onScroll);
64
65 // Initial check in case content is smaller than viewport height
66 onScroll();
67
68 // Load Scrolled Content
69 function loadContent() {
70 if (isLoading) return; // <-- ADD THIS
71 isLoading = true; // <-- ADD THIS
72 // Build adv filter data from block-wrapper element
73 filterValue =
74 typeof wrap.attr("data-filter_value") === "string"
75 ? JSON.parse(wrap.attr("data-filter_value"))
76 : (wrap.attr("data-filter_value") ?? []);
77
78 const advFilterData = {};
79
80 if (Array.isArray(filterValue) && filterValue.length > 0) {
81 advFilterData.isAdv = true;
82 advFilterData.filterShow = true;
83 advFilterData.checkFilter = true;
84 advFilterData.order = wrap.attr("data-filter_order") || "";
85 advFilterData.orderby = wrap.attr("data-filter_orderby") || "";
86 advFilterData.adv_sort = wrap.attr("data-filter_queryQuick") || "";
87 const authorData =
88 typeof wrap.attr("data-filter_author") === "string"
89 ? (JSON.parse(wrap.attr("data-filter_author")) ?? [])
90 : (wrap.attr("data-filter_author") ?? []);
91 if (Array.isArray(authorData) && authorData.length > 0) {
92 advFilterData.author = authorData;
93 }
94 }
95
96 // Forward active search term to paginated scroll requests
97 const searchVal = wrap.attr("data-filter_search") || "";
98 if (searchVal) {
99 advFilterData.search = searchVal;
100 if (!advFilterData.isAdv) {
101 advFilterData.isAdv = true;
102 advFilterData.filterShow = true;
103 advFilterData.checkFilter = true;
104 }
105 }
106
107 // Get the LATEST unique posts for this specific block on each call
108 const ultpCurrentUniquePosts = JSON.stringify(
109 wrap.find(".ultp-current-unique-posts").data("current-unique-posts"),
110 );
111
112 console.log(pageNum, "pageNum");
113
114 paginationAjaxCall({
115 wrap, // .ultp-block-wrapper Selector
116 pageNum,
117 blockid,
118 ultpNonce,
119 blockName,
120 post_ID,
121 filterType,
122 ultpCurrentUniquePosts,
123 widgetBlockId,
124 exclude, // exclude post ids
125 builder, // builder type/data
126 filterValue,
127 advFilterData,
128 onBeforeSend() {
129 return;
130 },
131 onSuccess(data) {
132 isLoading = false; // <-- ADD THIS
133 if (!data || data.trim() === "") {
134 noMoreData = true;
135 $(window).off("scroll.ultp-iscroll-" + blockid);
136 return;
137 }
138 if (!data || data.trim() === "") {
139 noMoreData = true;
140 $(window).off("scroll.ultp-iscroll-" + blockid);
141 return;
142 }
143 let incoming = $(data);
144 const uniquePostsDataEl = incoming.filter(
145 ".ultp-current-unique-posts",
146 );
147
148 if (uniquePostsDataEl.length > 0) {
149 // Update global session unique IDs from the server response
150 const newGlobalUniqueIds =
151 uniquePostsDataEl.data("ultp-unique-ids");
152 setSession("ultp_uniqueIds", JSON.stringify(newGlobalUniqueIds));
153
154 // Update the block's own list of current posts
155 const mainUniquePostsEl = wrap
156 .find(".ultp-current-unique-posts")
157 .first();
158 const existingBlockIds =
159 mainUniquePostsEl.data("current-unique-posts") || [];
160 const newBlockIds =
161 uniquePostsDataEl.data("current-unique-posts") || [];
162 const combinedBlockIds = [...existingBlockIds, ...newBlockIds];
163 mainUniquePostsEl.attr(
164 "data-current-unique-posts",
165 JSON.stringify(combinedBlockIds),
166 );
167
168 // Remove the data carrier div from the incoming content
169 incoming = incoming.not(uniquePostsDataEl);
170 }
171
172 const itemsWrap = wrap.find(".ultp-block-items-wrap");
173 itemsWrap.append(incoming);
174
175 // Animate only the newly added items
176 const newItems = itemsWrap.children().slice(-incoming.length);
177 animateBlockItem(newItems);
178
179 pageNum++;
180
181 // Check again if more content is needed to fill the viewport
182 onScroll();
183 },
184 });
185 }
186
187 // Calculate if user has scrolled near the end of the block
188 function isEndReached() {
189 const gridBottom = block.offset().top + block.outerHeight();
190 const scrollBottom = $(window).scrollTop() + $(window).height();
191 return scrollBottom >= gridBottom - 100;
192 }
193 };
194
195 // Card Item Animation Config.
196 function animateBlockItem(blockItems) {
197 if (blockItems.length > 0) {
198 blockItems.addClass("ultp-infscroll-animate-in");
199 if (!window.IntersectionObserver) {
200 blockItems.each(function (i) {
201 const block = $(this);
202 setTimeout(function () {
203 block.addClass("ultp-infscroll-visible");
204 }, i * 80);
205 });
206 return;
207 }
208
209 // Fire the animation only when each card actually enters the viewport
210 const observer = new IntersectionObserver(
211 function (entries) {
212 const visible = entries.filter(function (e) {
213 return e.isIntersecting;
214 });
215 visible.forEach(function (entry, i) {
216 setTimeout(function () {
217 $(entry.target).addClass("ultp-infscroll-visible");
218 }, i * 70); // stagger within each visible batch
219 observer.unobserve(entry.target);
220 });
221 },
222 { threshold: 0.08, rootMargin: "0px 0px -20px 0px" },
223 );
224
225 blockItems.each(function () {
226 observer.observe(this);
227 });
228 }
229 }
230 })(jQuery);
231