PageSourceSearch

https://indacloud.co/wp-content/themes/hello-theme-child-master/js/blog.js?ver=1.0.0

js indacloud.co collected 2026-10-01 14:01:29 UTC 9,171 bytes, 272 lines download raw bytes

1/**
2 * Blog Revamp — Filters, Pagination & AJAX Grid.
3 * Modifications: Abdullah Abbasi
4 * Task: Blog System Revamp
5 *
6 * Handles the interactive behaviour of the /blog listing page: category
7 * filter switching, AJAX-powered post grid loading, and pagination with
8 * smooth scroll-to-top.
9 *
10 *
11 * @package HelloElementorChild
12 */
13
14var blogAbortController = null;
15
16document.addEventListener('DOMContentLoaded', function () {
17	initBlogFilters();
18	initBlogPagination();
19});
20
21/**
22 * Show the slider section and hide the grid container.
23 *
24 * Called when the "All Posts" category is selected. Restores the default
25 * blog page view with horizontal content sliders.
26 *
27 * @return {void}
28 */
29function showSlidersHideGrid() {
30	var slidersSection = document.getElementById('blog-sliders-section');
31	var gridContainer = document.getElementById('blog-grid-container');
32	if (slidersSection) { slidersSection.style.display = 'block'; slidersSection.style.opacity = '1'; }
33	if (gridContainer) gridContainer.style.display = 'none';
34}
35
36/**
37 * Show the grid container and hide the slider section.
38 *
39 * Called when a specific category is selected. Displays the AJAX-powered
40 * post grid while hiding the sliders to avoid layout overlap.
41 *
42 * @return {void}
43 */
44function showGridHideSliders() {
45	var slidersSection = document.getElementById('blog-sliders-section');
46	var gridContainer = document.getElementById('blog-grid-container');
47	if (slidersSection) { slidersSection.style.display = 'none'; slidersSection.style.opacity = '1'; }
48	if (gridContainer) gridContainer.style.display = 'block';
49}
50
51/**
52 * Initialise the category filter bar with click event delegation.
53 *
54 * Attaches a single click handler to .blog-categories and uses event
55 * delegation to handle clicks on any .blog-cat-item button. When a
56 * category is selected:
57 *   - Active state is toggled on the clicked button.
58 *   - If category is "all", shows sliders and hides grid.
59 *   - If gridCache has pre-rendered HTML for the category, injects it
60 *     directly for instant display.
61 *   - Otherwise, triggers an AJAX fetch via fetchBlogPosts().
62 *
63 * @return {void}
64 */
65function initBlogFilters() {
66	document.querySelector('.blog-categories')?.addEventListener('click', function (e) {
67		var btn = e.target.closest('.blog-cat-item');
68		if (!btn) return;
69
70		/* When categoryRedirect is enabled, tabs link to real archive URLs — let the browser navigate. */
71		if (blogRevamp.categoryRedirect) {
72			return;
73		}
74
75		document.querySelectorAll('.blog-cat-item').forEach(function (el) {
76			el.classList.remove('active');
77		});
78		btn.classList.add('active');
79
80		var category = btn.getAttribute('data-category');
81
82		/* "All Posts" restores the default slider view — no AJAX needed. */
83		if (category === 'all') {
84			showSlidersHideGrid();
85			return;
86		}
87
88		var container = document.getElementById('blog-grid-container');
89		if (!container) return;
90
91		/* GridCache hit — pre-rendered HTML from wp_localize_script, instant display. */
92		if (blogRevamp.gridCache && blogRevamp.gridCache[category]) {
93			container.innerHTML = blogRevamp.gridCache[category];
94			container.style.opacity = '1';
95			showGridHideSliders();
96			return;
97		}
98
99		/* GridCache miss — show loading state on whichever section is currently visible. */
100		var slidersSection = document.getElementById('blog-sliders-section');
101		var gridVisible = window.getComputedStyle(container).display !== 'none';
102
103		if (gridVisible) {
104			container.style.opacity = '0.5';
105		} else if (slidersSection) {
106			slidersSection.style.opacity = '0.5';
107		}
108
109		fetchBlogPosts(category, 1);
110	});
111}
112
113/**
114 * Initialise pagination click interception on the blog grid.
115 *
116 * Attaches a click handler to #blog-grid-container and intercepts clicks
117 * on .blog-page-link elements. Prevents default navigation and converts
118 * the click to an AJAX request via fetchBlogPosts().
119 *
120 * Page number resolution order:
121 *   1. data-page attribute on the clicked link.
122 *   2. Query string parameter (?paged=N or ?page=N).
123 *   3. Path-based parameter (/page/N).
124 *
125 * @return {void}
126 */
127function initBlogPagination() {
128	document.getElementById('blog-grid-container')?.addEventListener('click', function (e) {
129		var link = e.target.closest('.blog-page-link');
130		if (!link || link.classList.contains('active')) return;
131
132		e.preventDefault();
133
134		var nav = link.closest('.blog-pagination');
135		if (!nav) return;
136
137		var category = nav.getAttribute('data-category');
138		var page = link.getAttribute('data-page');
139
140		/* Fallback: parse page number from URL if data-page attribute is missing. */
141		if (!page) {
142			var href = link.href || link.getAttribute('href');
143			var qsMatch = href.match(/[?&]paged?=(\d+)/);
144			if (qsMatch) {
145				page = qsMatch[1];
146			} else {
147				var pathMatch = href.match(/\/page\/(\d+)/);
148				if (pathMatch) page = pathMatch[1];
149			}
150		}
151
152		link.classList.add('loading');
153
154		var container = document.getElementById('blog-grid-container');
155		if (container) {
156			container.style.opacity = '0.5';
157		}
158
159		fetchBlogPosts(category, parseInt(page || 1), true);
160	});
161}
162
163/**
164 * Remove the loading spinner class from all pagination links.
165 *
166 * Resets the UI state after a pagination request completes (success or
167 * failure). Called in both the .then() and .catch() handlers of the
168 * fetch promise.
169 *
170 * @return {void}
171 */
172function removePaginationLoader() {
173	document.querySelectorAll('.blog-page-link.loading').forEach(function (el) {
174		el.classList.remove('loading');
175	});
176}
177
178/**
179 * Fetch blog posts via AJAX and inject the grid HTML into the DOM.
180 *
181 * Main data-fetching function for the blog grid. Handles three scenarios:
182 *   1. Cache hit — if page 1 and gridCache has the category, use it directly.
183 *   2. Cache miss — make AJAX request to WordPress admin-ajax endpoint.
184 *   3. Pagination — always makes AJAX request regardless of cache.
185 *
186 * Uses AbortController to cancel any in-flight request before starting
187 * a new one. This prevents race conditions when the user switches
188 * categories rapidly.
189 *
190 * On successful response:
191 *   - Grid HTML is injected into #blog-grid-container.
192 *   - Sliders are hidden, grid is shown.
193 *   - Page 1 responses are cached in gridCache for instant future access.
194 *   - Viewport scrolls to top after a 100ms delay.
195 *
196 * On error:
197 *   - AbortError is silently ignored (expected during rapid switching).
198 *   - All other errors restore opacity and remove loading spinners.
199 *
200 * @param {string}  category    The category slug or ID to filter by.
201 * @param {number}  page        The page number to fetch (1-indexed).
202 * @param {boolean} isPagination Whether this request originated from a
203 *                               pagination click (bypasses cache).
204 * @return {void}
205 */
206function fetchBlogPosts(category, page, isPagination) {
207	var container = document.getElementById('blog-grid-container');
208	if (!container) return;
209
210	/* Cancel any in-flight request to prevent race conditions from rapid category switching. */
211	if (blogAbortController) {
212		blogAbortController.abort();
213	}
214	blogAbortController = new AbortController();
215	var signal = blogAbortController.signal;
216
217	/* Cache hit for page 1 — inject pre-rendered HTML without making an AJAX call. */
218	if (page === 1 && !isPagination && blogRevamp.gridCache && blogRevamp.gridCache[category]) {
219		container.innerHTML = blogRevamp.gridCache[category];
220		container.style.opacity = '1';
221		showGridHideSliders();
222		removePaginationLoader();
223		return;
224	}
225
226	/* Build FormData for WordPress admin-ajax.php endpoint. */
227	var formData = new FormData();
228	formData.append('action', 'blog_filter');
229	formData.append('category', category);
230	formData.append('page', page);
231	formData.append('_ajax_nonce', blogRevamp.nonce);
232	if (isPagination) {
233		formData.append('pagination', '1');
234	}
235
236	fetch(blogRevamp.ajaxUrl, {
237		method: 'POST',
238		body: formData,
239		signal: signal,
240	})
241		.then(function (res) { return res.json(); })
242		.then(function (data) {
243			if (data.success) {
244				container.innerHTML = data.data.grid_html;
245				container.style.opacity = '1';
246				showGridHideSliders();
247				/* Cache page 1 responses for instant category switching on subsequent visits. */
248				if (blogRevamp.gridCache && page === 1) {
249					blogRevamp.gridCache[category] = data.data.grid_html;
250				}
251			}
252			removePaginationLoader();
253			/* Delay scroll-to-top by 100ms to allow DOM injection to complete before viewport moves. */
254			setTimeout(function() {
255				var container = document.getElementById('blog-grid-container');
256				if (container) {
257					window.scrollTo({ top: 0, behavior: 'smooth' });
258					document.documentElement.scrollTo({ top: 0, behavior: 'smooth' });
259					document.body.scrollTo({ top: 0, behavior: 'smooth' });
260				}
261			}, 100); 
262		})
263		.catch(function (err) {
264			/* AbortError is expected when the user switches categories rapidly. */
265			if (err.name === 'AbortError') return;
266			/* For real errors, restore opacity and remove loading spinners so the UI doesn't stay frozen. */
267			container.style.opacity = '1';
268			var slidersSection = document.getElementById('blog-sliders-section');
269			if (slidersSection) slidersSection.style.opacity = '1';
270			removePaginationLoader();
271		});
272}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.