PageSourceSearch

https://yourpacesetter.com/wp-content/plugins/post-carousel/blocks/assets/js/builder-scripts.js?ver=4.0.8

js yourpacesetter.com collected 2026-09-29 12:25:30 UTC 96,857 bytes, 3,495 lines download raw bytes

1( function () {
2    window.addEventListener( 'elementor/frontend/init', function () {
3        elementorFrontend.hooks.addAction(
4            'frontend/element_ready/smart_post_show_pro_template.default',
5            function ( $scope ) {
6                if ( typeof init === 'function' ) {
7                    init();
8                }
9            }
10        );
11    } );
12} )();
13
14function init() {
15	// Social link copy function.
16	const socialLinkCopy = () => {
17		const socialLinks = document.querySelectorAll(
18			'.sp-smart-post-social-share .sp-smart-post-copy-btn'
19		);
20
21		if (0 < socialLinks.length) {
22			socialLinks.forEach((element) => {
23				element.addEventListener('click', (e) => {
24					e.preventDefault();
25					const link = e.target
26						.closest('.sp-smart-post-copy-btn')
27						.getAttribute('data-url');
28
29					if (link && navigator.clipboard) {
30						navigator.clipboard.writeText(link);
31					} else {
32						console.log(
33							'Clipboard API not supported or link missing.'
34						);
35					}
36				});
37			});
38		}
39	};
40
41	// Post Modal custom lightbox.
42	const modal = () => {
43		const modalContainers = document.querySelectorAll(
44			'.sp-smart-post-modal-container'
45		);
46		let imageSize;
47
48		// Utility: Get next or previous post ID based on current
49		const getNextPostId = (direction, currentId, allIds) => {
50			const index = allIds.indexOf(String(currentId));
51			if (index === -1) {
52				return currentId;
53			}
54			if (direction === 'next') {
55				return allIds[(index + 1) % allIds.length];
56			} else if (direction === 'prev') {
57				return allIds[(index - 1 + allIds.length) % allIds.length];
58			}
59			return currentId;
60		};
61
62		const getReadingTime = (content, attr) => {
63			const text = content.trim();
64			const characterCount = text.length;
65			const wordCount = text.split(/\s+/).filter(Boolean).length;
66			const allCount = {
67				words: wordCount,
68				chars: characterCount,
69			};
70			attr = JSON.parse(attr);
71			const type = attr?.unit;
72			return `${Math.floor(
73				parseInt(allCount[type]) / parseInt(attr.value)
74			)} Min Read`;
75		};
76		const sendPostIdAjax = (postId, modal) => {
77			fetch(sp_smart_post_block_localize.ajaxUrl, {
78				method: 'POST',
79				headers: {
80					'Content-Type': 'application/x-www-form-urlencoded',
81				},
82				body: new URLSearchParams({
83					action: 'sp_handle_post_id',
84					nonce: sp_smart_post_block_localize.ajaxNonce,
85					post_id: postId,
86					image_size: imageSize,
87				}),
88			})
89				.then((res) => res.json())
90				.then((data) => {
91					if (data.success) {
92						const postData = data.data;
93						const modalImage = postData.post_image;
94						const modalTitle = postData.title;
95						const modalAuthor = postData.author_name;
96						const modalDate = postData.date_time;
97						const modalTaxonomy = postData.meta_taxonomy;
98						const modalBadges = postData.post_badges_list;
99						const modalContent = postData.content.replace(
100							/^"|"$/g,
101							''
102						);
103						const modalComment = postData.post_data.comment_count;
104						const modalViews = postData.post_views;
105						const modalLike = postData.like_button;
106						const readingTimeContainer = modal.querySelector(
107							'.sp-smart-post-reading-time'
108						);
109						const readValue = readingTimeContainer
110							? readingTimeContainer.dataset.readTime
111							: '';
112						let readTime;
113						if (readValue) {
114							readTime = getReadingTime(
115								modalContent.replace(/<\/?p>/g, ''),
116								readValue
117							);
118						}
119
120						modal.querySelector(
121							'.sp-smart-post-card-modal-image'
122						).innerHTML = modalImage;
123						modal.querySelector(
124							'.sp-post-modal-title'
125						).textContent = modalTitle;
126						const authorEl = modal.querySelector('.sp-meta-author');
127						if (authorEl) {
128							authorEl.innerText = modalAuthor;
129						}
130						const dateEl = modal.querySelector('.sp-meta-date');
131						if (dateEl) {
132							dateEl.innerText = modalDate;
133						}
134						const commentsEl =
135							modal.querySelector('.sp-meta-comments');
136						if (commentsEl) {
137							commentsEl.innerText = modalComment;
138						}
139						const viewsEl = modal.querySelector('.sp-meta-views');
140						if (viewsEl) {
141							viewsEl.innerText = modalViews;
142						}
143						const likesEl = modal.querySelector(
144							'.sp-smart-post-likes'
145						);
146						if (likesEl) {
147							likesEl.innerHTML = modalLike;
148						}
149						const readTimeEl = modal.querySelector(
150							'.sp-meta-reading-time'
151						);
152						if (readTimeEl) {
153							readTimeEl.innerHTML = readTime;
154						}
155
156						const postBadgesEl = modal.querySelector(
157							'.sp-title-badges-list'
158						);
159						if (
160							postBadgesEl &&
161							modalBadges &&
162							modalBadges?.length > 0
163						) {
164							const listItems = modalBadges
165								.map(
166									(item) =>
167										`<li class="sp-title-badge-item">${item.name}</li>`
168								)
169								?.join('');
170							postBadgesEl.innerHTML = listItems;
171						}
172
173						modal.querySelector(
174							'.sp-post-modal-excerpt'
175						).innerHTML = modalContent;
176						modal.querySelector(
177							'.sp-meta-taxonomy-category'
178						).innerText = modalTaxonomy;
179
180						setTimeout(() => {
181							modal.style.opacity = 1;
182						}, 300);
183					} else {
184						console.log('PHP error:', data.data);
185					}
186				})
187				.catch((err) => {
188					console.log('Fetch error:', err);
189				});
190		};
191
192		const cleanData = (modal) => {
193			modal.querySelector('.sp-smart-post-card-modal-image').innerHTML =
194				'';
195			modal.querySelector('.sp-post-modal-title').textContent = '';
196			modal.querySelector('.sp-meta-taxonomy-category').innerText = '';
197			modal.querySelector('.sp-post-modal-excerpt').innerHTML = '';
198		};
199
200		// Open modal and setup navigation
201		const openModal = (e, container) => {
202			e.preventDefault();
203			let modalData;
204
205			const modal = container.querySelector(
206				'.sp-smart-post-modal-container'
207			);
208
209			imageSize = container.querySelector(
210				'.sp-smart-post-modal-container .sp-smart-post-card-modal-image'
211			).dataset.imageSize;
212
213			const clickedCard = e.target.closest('.sp-smart-post-card');
214			const clickedTitle = clickedCard?.querySelector(
215				'.sp-smart-post-title-wrapper'
216			);
217
218			if (!clickedTitle) {
219				return;
220			}
221
222			let activePostId = String(clickedTitle.dataset.postId); // Initialize properly
223			const allTitles = container.querySelectorAll(
224				'.sp-smart-post-title-wrapper'
225			);
226			const allIds = [
227				...new Set(
228					Array.from(allTitles).map((item) => item.dataset.postId)
229				),
230			];
231			const nextBtn = container.querySelector('.sp-smart-modal-next');
232			const prevBtn = container.querySelector('.sp-smart-modal-prev');
233
234			// sendPostIdAjax( clickedTitle.dataset.postId, modal );
235			// Setup navigation button handlers
236			const setupNav = (btn, direction) => {
237				if (!btn) {
238					return;
239				}
240				btn.onclick = () => {
241					activePostId = getNextPostId(
242						direction,
243						activePostId,
244						allIds
245					);
246					//	modal.style.opacity = 0;
247					sendPostIdAjax(activePostId, modal);
248				};
249			};
250
251			setupNav(nextBtn, 'next');
252			setupNav(prevBtn, 'prev');
253
254			// modal.style.display = "block";
255			modal.classList.add('is_open');
256		};
257
258		// Close modal
259		const closeModal = (closeBtn) => {
260			const modal = closeBtn.closest('.sp-smart-post-modal-container');
261			// if ( modal ) modal.style.display = "none";
262
263			modal.style.opacity = 0;
264			if (modal) {
265				modal.classList.remove('is_open');
266			}
267			cleanData(modal);
268		};
269
270		// Attach modal close events
271		modalContainers.forEach((modal) => {
272			const box = modal.querySelector('.sp-smart-post-modal-content');
273			const nextBtn = modal.querySelector('.sp-smart-modal-next');
274			const prevBtn = modal.querySelector('.sp-smart-modal-prev');
275			modal
276				.querySelectorAll('.sp-modal-close-btn.cursor')
277				.forEach((btn) => {
278					btn.addEventListener('click', () => closeModal(btn));
279				});
280			modal.addEventListener('click', (event) => {
281				const clickedEl = event.target;
282				// If click is NOT inside box AND not on next/prev buttons
283				if (
284					!box.contains(clickedEl) &&
285					clickedEl !== nextBtn &&
286					clickedEl !== prevBtn &&
287					(!nextBtn || !nextBtn.contains(clickedEl)) &&
288					(!prevBtn || !prevBtn.contains(clickedEl))
289				) {
290					closeModal(box);
291				}
292			});
293		});
294
295		// Attach open modal triggers using event delegation for better performance
296		modalContainers.forEach((modal) => {
297			if (!modal.textContent.trim()) {
298				return;
299			}
300
301			const container = modal.parentElement;
302
303			container.addEventListener('click', (e) => {
304				// Do not trigger if the click is inside an already open modal.
305				if (e.target.closest('.sp-smart-post-modal-container')) {
306					return;
307				}
308
309				const trigger = e.target.closest(
310					'.sp-smart-post-card-image a, .sp-smart-post-title-wrapper, .sp-smart-post-read-more-button a'
311				);
312
313				if (!trigger) {
314					return;
315				}
316
317				const clickedCard = trigger.closest('.sp-smart-post-card');
318				if (!clickedCard) {
319					return;
320				}
321
322				const clickedTitle = clickedCard.querySelector(
323					'.sp-smart-post-title-wrapper'
324				);
325				if (!clickedTitle || !clickedTitle.dataset.postId) {
326					return;
327				}
328
329				e.preventDefault();
330				modal.style.opacity = 0;
331				sendPostIdAjax(clickedTitle.dataset.postId, modal);
332				openModal(e, container);
333			});
334		});
335	};
336
337	// Initialize image gallery and video players.
338	const initSmartPostFeatures = (context = document) => {
339		// --- Slider Init ---
340		const sliderWrappers = context.querySelectorAll('.sp-slider-wrapper');
341
342		sliderWrappers.forEach((slideWrapper) => {
343			if (!slideWrapper.classList.contains('sp-slider-initialized')) {
344				new SPSlider(slideWrapper, {
345					loop: true,
346					autoplay: true,
347					interval: 3000,
348					speed: 600,
349				});
350				slideWrapper.classList.add('sp-slider-initialized');
351			}
352		});
353
354		// --- Video Player Init ---
355		const videoPostList = context.querySelectorAll(
356			'.sp-smart-video-player'
357		);
358
359		videoPostList.forEach((videoContainer) => {
360			if (!videoContainer.classList.contains('sp-video-initialized')) {
361				const videoUrl = videoContainer.dataset.video_url;
362				const featureImage = videoContainer.dataset.image_url;
363				const videoCaption = videoContainer.dataset.video_caption;
364
365				new SpSmartVideoPlayer(videoContainer, videoUrl, {
366					featureImage,
367					videoCaption,
368					showFeatureImage: true,
369					transitionSpeed: 500,
370				});
371				videoContainer.classList.add('sp-video-initialized');
372			}
373			videoContainer.addEventListener('click', function (event) {
374				event.preventDefault();
375				event.stopPropagation();
376
377				const featureVideo = videoContainer.querySelector('video');
378				if (featureVideo) {
379					if (featureVideo.paused) {
380						featureVideo.play();
381					} else {
382						featureVideo.pause();
383					}
384				}
385			});
386		});
387	};
388
389	initSmartPostFeatures();
390
391	socialLinkCopy();
392
393	modal();
394	/**
395	 * Carousel Pagination Function.
396	 * @param paginationClass
397	 */
398	const paginationDotNumber = (paginationClass) => {
399		return {
400			el: paginationClass,
401			clickable: true,
402			renderBullet(index, className) {
403				return (
404					'<span class="' + className + '">' + (index + 1) + '</span>'
405				);
406			},
407		};
408	};
409	/**
410	 * Helper to safely parse JSON.
411	 * @param str
412	 * @param fallback
413	 */
414	const safeJSONParse = (str, fallback = {}) => {
415		try {
416			return JSON.parse(str) || fallback;
417		} catch (e) {
418			console.log('Failed to parse JSON:', str, e);
419			return fallback;
420		}
421	};
422
423	/**
424	 * Initializes Timeline layout with dynamic height adjustment.
425	 */
426	document
427		.querySelectorAll('.sp-smart-post-timeline-three')
428		.forEach((containerEl) => {
429			const swiperEl = containerEl.querySelector('.swiper-container');
430			if (!swiperEl) {
431				return;
432			}
433			const getBlockId = containerEl.getAttribute('id') || '';
434			const blockId = getBlockId ? `#${getBlockId}` : '';
435
436			const postContainers = containerEl.querySelectorAll(
437				`${blockId} .sp-smart-post-timeline-three-post-container`
438			);
439			const wrapper = document.querySelector(
440				`${blockId} .timeline-three-layout-two .swiper-wrapper`
441			);
442			const timelineBorder = document.querySelector(
443				`${blockId} .timeline-three-layout-two .sp-smart-post-timeline-border`
444			);
445
446			// Calculate max height from posts.
447			let maxHeight = 0;
448			postContainers.forEach((post) => {
449				maxHeight = Math.max(maxHeight, post.clientHeight);
450			});
451			maxHeight += 60; // Add margin
452
453			// Apply calculated height
454			if (wrapper) {
455				wrapper.style.marginTop = `${maxHeight}px`;
456			}
457			if (timelineBorder) {
458				timelineBorder.style.marginTop = `${maxHeight}px`;
459			}
460
461			const options = safeJSONParse(
462				swiperEl.getAttribute('data-swiper-options')
463			);
464			if (!Object.keys(options).length) {
465				return;
466			}
467
468			new PCPSwiper(swiperEl, options);
469		});
470
471	/**
472	 * Initializes thumbnail sliders (layout one).
473	 */
474	document
475		.querySelectorAll(
476			'.sp-smart-post-thumbnail-slider.sp-smart-post-block-wrapper'
477		)
478		.forEach((containerEl) => {
479			const [mainSwiperEl, thumbsSwiperEl] =
480				containerEl.querySelectorAll('.swiper-container');
481			const thumbsOptions = safeJSONParse(
482				containerEl
483					.querySelector('.sp-smart-post-swiper2')
484					?.getAttribute('data-swiper-options')?.replace(/u0022/g, '"')
485			);
486			const mainOptions = safeJSONParse(
487				mainSwiperEl?.getAttribute('data-swiper-options')?.replace(/u0022/g, '"')
488			);
489
490			if (
491				!mainSwiperEl ||
492				!thumbsSwiperEl ||
493				!Object.keys(mainOptions).length
494			) {
495				return;
496			}
497
498			const thumbsSwiper = new PCPSwiper(thumbsSwiperEl, thumbsOptions);
499			const carouselPagination = mainOptions?.pagination;
500			const paginationClassName = carouselPagination?.el;
501			const numberPagination = mainOptions?.pagination?.paginationType
502				? true
503				: false;
504			const mainSwiper = new PCPSwiper(mainSwiperEl, {
505				...mainOptions,
506				thumbs: { swiper: thumbsSwiper },
507				pagination: !numberPagination
508					? carouselPagination
509					: paginationDotNumber(paginationClassName),
510			});
511		});
512
513	/**
514	 * Initializes thumbnail sliders (layout two).
515	 */
516	document
517		.querySelectorAll(
518			'.sp-smart-post-block-wrapper.sp-smart-thumbnail-slider-two'
519		)
520		.forEach((containerEl) => {
521			const [mainSwiperEl, thumbsSwiperEl] =
522				containerEl.querySelectorAll('.swiper-container');
523			const thumbsOptions = safeJSONParse(
524				containerEl
525					.querySelector('.sp-smart-post-swiper2')
526					?.getAttribute('data-swiper-options')?.replace(/u0022/g, '"')
527			);
528			const mainOptions = safeJSONParse(
529				mainSwiperEl?.getAttribute('data-swiper-options')?.replace(/u0022/g, '"')
530			);
531
532			if (
533				!mainSwiperEl ||
534				!thumbsSwiperEl ||
535				!Object.keys(mainOptions).length
536			) {
537				return;
538			}
539
540			const thumbsSwiper = new PCPSwiper(thumbsSwiperEl, thumbsOptions);
541			const mainSwiper = new PCPSwiper(mainSwiperEl, {
542				...mainOptions,
543				thumbs: { swiper: thumbsSwiper },
544			});
545		});
546
547	/**
548	 * Throttles a function using requestAnimationFrame for performance.
549	 * @param {Function} callback The function to throttle.
550	 * @return {Function} The throttled function.
551	 */
552	const throttle = (callback) => {
553		let ticking = false;
554		return (...args) => {
555			if (!ticking) {
556				window.requestAnimationFrame(() => {
557					callback(...args);
558					ticking = false;
559				});
560				ticking = true;
561			}
562		};
563	};
564
565	/**
566	 * Initializes and manages scroll-based animations for all timeline blocks on the page.
567	 * Caches DOM elements and uses a single throttled scroll listener for better performance.
568	 */
569	const initTimelineScroll = () => {
570		const allTimelinesData = [];
571		document
572			.querySelectorAll('.sp-smart-post-show-scroll-wrapper')
573			.forEach((timelineWrapper) => {
574				const blockId = timelineWrapper.id;
575				if (!blockId) {
576					return;
577				}
578
579				const postCards = timelineWrapper.querySelectorAll(
580					'.sp-smart-post-timeline-one-post-container .sp-smart-indicator-circle'
581				);
582				const indicatorArrows = timelineWrapper.querySelectorAll(
583					'.sp-smart-post-timeline-one-post-container .sp-smart-indicator-arrow'
584				);
585				const timelineContainer = timelineWrapper.querySelector(
586					'.sp-smart-post-timeline-container'
587				);
588
589				// Pre-create or find the style tag for this instance to avoid creating it on every scroll.
590				let styleTag = timelineWrapper.querySelector(
591					'style.sps-dynamic-styles'
592				);
593				if (!styleTag) {
594					styleTag = document.createElement('style');
595					styleTag.className = 'sps-dynamic-styles';
596					timelineWrapper.insertBefore(
597						styleTag,
598						timelineWrapper.firstChild
599					);
600				}
601
602				if (timelineContainer) {
603					allTimelinesData.push({
604						wrapper: timelineWrapper,
605						blockId,
606						postCards,
607						indicatorArrows,
608						timelineContainer,
609						styleTag,
610					});
611				}
612			});
613
614		// 2. Skip if no timelines are found
615		if (allTimelinesData.length === 0) {
616			return;
617		}
618
619		// 3. Create a single, efficient scroll handler for all timelines
620		const handleTimelineScrolls = () => {
621			const scrollY = window.scrollY;
622			const pageHeight = Math.max(document.body.offsetHeight);
623
624			allTimelinesData.forEach((data) => {
625				const wrapperRect = data.wrapper.getBoundingClientRect();
626
627				// Only process timelines currently visible in the viewport (with a buffer)
628				if (
629					wrapperRect.bottom >= 0 &&
630					wrapperRect.top <= window.innerHeight
631				) {
632					const scrollPosition = scrollY + 200;
633
634					// Indicator activation logic
635					const indicatorActive = (elements) => {
636						elements.forEach((el) => {
637							const elTop =
638								el.getBoundingClientRect().top + scrollY;
639							if (
640								scrollY + 505 > elTop ||
641								scrollPosition + 700 >= pageHeight
642							) {
643								el.classList.add('active');
644							} else {
645								el.classList.remove('active');
646							}
647						});
648					};
649					indicatorActive(data.postCards);
650					indicatorActive(data.indicatorArrows);
651
652					// Timeline line height calculation logic
653					const timelineRect =
654						data.timelineContainer.getBoundingClientRect();
655					const timelineTop = timelineRect.top + scrollY;
656					let height = 320;
657					let heightUnit = 'px';
658
659					if (
660						timelineRect.bottom - 518 < 0 ||
661						scrollPosition + 700 >= pageHeight
662					) {
663						height = 100;
664						heightUnit = '%';
665					} else if (
666						scrollPosition > timelineTop &&
667						timelineRect.bottom - 518 > 0
668					) {
669						height = scrollPosition + 320 - timelineTop;
670					}
671					// Update the dedicated style tag's content, which is more performant than creating new tags.
672					const styleContent = `#${data.blockId} .sp-smart-post-timeline-container::after { height: ${height}${heightUnit} !important; }`;
673					if (data.styleTag.textContent !== styleContent) {
674						data.styleTag.textContent = styleContent;
675					}
676				}
677			});
678		};
679
680		// 4. Add the single throttled listener
681		window.addEventListener('scroll', throttle(handleTimelineScrolls));
682	};
683
684	// Initialize the timeline scroll animations.
685	initTimelineScroll();
686	function updatePaginationData(section, data) {
687		if (!section || !data) {
688			return;
689		}
690		// Update dataset attributes.
691		section.dataset.pages = data.total_pages;
692		section.dataset.current = data.current_page;
693		if (section?.dataset.pages < 2) {
694			section.style.display = 'none';
695		} else {
696			section.style.display = 'flex';
697		}
698		if (section?.dataset.pages < 2) {
699			return false;
700		}
701		updatePaginationUI(section);
702		createPaginationSection(section);
703	}
704	const createPaginationSection = (section) => {
705		const totalPages = parseInt(section.dataset.pages, 10);
706		const currentPage = parseInt(section.dataset.current, 10);
707		const paginationtype = section?.dataset.paginationtype;
708		if (paginationtype == 'pagination') {
709			if (!totalPages || totalPages < 2) {
710				return;
711			}
712
713			const paginationContainer = section.querySelector(
714				'.sp-smart-post-pagination-buttons'
715			);
716			if (!paginationContainer) {
717				return;
718			}
719
720			paginationContainer.innerHTML = ''; // Clear existing buttons
721
722			// Previous Button
723			const prevBtn = document.createElement('a');
724			prevBtn.href = '#';
725			prevBtn.className = 'page-numbers prev';
726			if (currentPage === 1) {
727				prevBtn.classList.add('disabled');
728			}
729			prevBtn.innerHTML = `<i class="sp-icon-left-open"></i> Previous`;
730			paginationContainer.appendChild(prevBtn);
731
732			// Number Buttons
733			for (let i = 1; i <= totalPages; i++) {
734				const pageBtn = document.createElement('a');
735				pageBtn.href = '#';
736				pageBtn.className = 'page-numbers';
737				pageBtn.dataset.page = i;
738				pageBtn.textContent = i;
739
740				if (i === currentPage) {
741					pageBtn.classList.add('current');
742				}
743
744				paginationContainer.appendChild(pageBtn);
745			}
746
747			// Next Button
748			const nextBtn = document.createElement('a');
749			nextBtn.href = '#';
750			nextBtn.className = 'page-numbers next';
751			if (currentPage === totalPages) {
752				nextBtn.classList.add('disabled');
753			}
754			nextBtn.innerHTML = `Next <i class="sp-icon-right-open"></i>`;
755			paginationContainer.appendChild(nextBtn);
756		}
757	};
758
759	const updatePaginationUI = (section) => {
760		const current = parseInt(section.dataset.current, 10);
761		const total = parseInt(section.dataset.pages, 10);
762		const paginationtype = section?.dataset.paginationtype;
763
764		section.querySelectorAll('.page-numbers[data-page]').forEach((link) => {
765			const page = parseInt(link.dataset.page, 10);
766			link.classList.toggle('current', page === current);
767		});
768		const prev = section.querySelector('.page-numbers.prev');
769		const next = section.querySelector('.page-numbers.next');
770		const loadMoreWrapper = section.querySelector(
771			'.sp-smart-post-load-more-button'
772		);
773		if (prev) {
774			prev.classList.toggle('disabled', current <= 1);
775		}
776		if (next) {
777			next.classList.toggle('disabled', current >= total);
778		}
779		// For nav-arrow buttons.
780		const [prevNav, nextNav] = section.querySelectorAll(
781			'.sp-smart-post-grid-nav-arrow-btn'
782		);
783		if (prevNav && nextNav) {
784			prevNav.style.pointerEvents = current <= 1 ? 'none' : 'auto';
785			prevNav.style.opacity = current <= 1 ? '0.5' : '1';
786			nextNav.style.pointerEvents = current >= total ? 'none' : 'auto';
787			nextNav.style.opacity = current >= total ? '0.5' : '1';
788		}
789		if (loadMoreWrapper) {
790			if (current >= total) {
791				const loadMoreWrapperBtn = loadMoreWrapper.querySelector('a');
792				if (loadMoreWrapperBtn) {
793					loadMoreWrapperBtn.style.display = 'none';
794				}
795			} else {
796				loadMoreWrapper.style.display = 'block';
797			}
798		}
799	};
800	function hasFilterCounts(count_data) {
801		if (!count_data || typeof count_data !== 'object') {
802			return false;
803		}
804
805		return Object.entries(count_data).some(([key, value]) => {
806			// Skip pagination
807			if (key === 'pagination') {
808				return false;
809			}
810			// Check if it's a non-empty array
811			return Array.isArray(value) && value.length > 0;
812		});
813	}
814	function getBlockParams() {
815		const url = new URL(window.location.href);
816		const params = new URLSearchParams(url.search);
817		const blockParams = {};
818		for (const [key, value] of params.entries()) {
819			if (
820				key === 'block' ||
821				key.startsWith('tx_') ||
822				key.startsWith('sps_')
823			) {
824				blockParams[key] = value;
825			}
826		}
827		return blockParams;
828	}
829
830	function updateSelectByParams(params, blockParent) {
831		// Loop through each param and try to update the matching <select>
832		for (const key in params) {
833			if ('sps_page' === key) {
834				const value = params[key];
835				const pagination_section = blockParent.querySelector(
836					'.sp-smart-post-pagination-section'
837				);
838				pagination_section.dataset.current = value;
839			} else if ('sps_search' === key) {
840				const search_input = blockParent.querySelector(
841					`input[name="${key}"]`
842				);
843				const value = params[key];
844				search_input.value = value;
845			} else if ('sps_date' === key) {
846				const selectDate = blockParent.querySelector(
847					'.sp-smart-post-show-date-filter-date-value'
848				);
849				const value = params[key];
850				const formatted = value
851					.replace(/^from-/, '')
852					.replace(/-to-/, ' - ');
853
854				// selectDate.innerText = formatted;
855				if (selectDate) {
856					selectDate.innerText = formatted;
857				}
858			} else if ('sps_preset_date' === key) {
859				const slectorData = blockParent.querySelector(
860					'.sp-smart-post-live-filter-dropdown-date, .sp-smart-post-live-filter-button-date'
861				);
862
863				const presetType = slectorData.dataset.presetType;
864				const labels = {
865					today: 'Today',
866					yesterday: 'Yesterday',
867					lastSevenDays: 'Last 7 Days',
868					lastThirtyDays: 'Last 30 Days',
869					thisWeek: 'This Week',
870					lastWeek: 'Last Week',
871					thisMonth: 'This Month',
872					lastMonth: 'Last Month',
873					thisYear: 'This Year',
874				};
875				const value = params[key];
876				const label = labels[value];
877
878				if (presetType === 'dropdown') {
879					const selectDate = blockParent.querySelector(
880						'.sp-smart-post-show-date-filter-date-value'
881					);
882					selectDate.innerText = label;
883				}
884
885				const allLinks = slectorData.querySelectorAll('li > a');
886				allLinks.forEach((link) => {
887					if (link.textContent.trim() === label) {
888						link.classList.add('active');
889					} else {
890						// Remove active from other links if needed
891						link.classList.remove('active');
892					}
893				});
894			} else {
895				const select = blockParent.querySelector(
896					`select[name="${key}"]`
897				);
898				if (select) {
899					const value = params[key];
900					// Set value if option exists.
901					const option = select.querySelector(
902						`option[value="${value}"]`
903					);
904					if (option) {
905						option.disabled = false;
906						option.selected = true;
907						select.value = value;
908						// Optional: trigger change event
909						// select.dispatchEvent(new Event('change'));
910					}
911				}
912			}
913		}
914	}
915
916	/**
917	 * Groups slides into swiper-slide wrappers when using specific effects
918	 * @param {HTMLElement} containerEl                                         - The swiper container element
919	 * @param {Object}      sps_swiper_option                                   - Swiper configuration options
920	 * @param {string[]}    [effectsRequiringWrapping=['fade', 'cube', 'flip']] - Effects that need slide wrapping
921	 */
922	function wrapSlidesForEffect(
923		containerEl,
924		sps_swiper_option,
925		effectsRequiringWrapping = ['fade', 'cube', 'flip']
926	) {
927		// Check if we need to wrap slides
928		if (
929			sps_swiper_option?.effect &&
930			effectsRequiringWrapping.includes(sps_swiper_option.effect)
931		) {
932			// Get valid slidesPerView (minimum 1)
933			const slidesPerView = Math.max(
934				1,
935				parseInt(sps_swiper_option?.slidesPerView) || 1
936			);
937			// Only proceed if we need multiple slides per view
938			if (slidesPerView > 1) {
939				const swiperWrapper =
940					containerEl.querySelector('.swiper-wrapper');
941				const loopItems =
942					containerEl.querySelectorAll('.sp-slide-item');
943				loopItems.forEach((item) => {
944					item.classList.remove('swiper-slide');
945				});
946				if (swiperWrapper && loopItems.length > 0) {
947					// Create document fragment for better performance
948					const fragment = document.createDocumentFragment();
949					// Group slides into chunks
950					for (let i = 0; i < loopItems.length; i += slidesPerView) {
951						const slideWrapper = document.createElement('div');
952						slideWrapper.className = 'swiper-slide';
953
954						// Add slides to this group
955						const endIndex = Math.min(
956							i + slidesPerView,
957							loopItems.length
958						);
959						for (let j = i; j < endIndex; j++) {
960							slideWrapper.appendChild(
961								loopItems[j].cloneNode(true)
962							);
963						}
964						fragment.appendChild(slideWrapper);
965					}
966
967					// Clear existing content and add new grouped slides
968					swiperWrapper.innerHTML = '';
969					swiperWrapper.appendChild(fragment);
970				}
971			}
972		}
973	}
974	const selected_params = getBlockParams();
975	// Loop over each Smart Post block container.
976
977	document.querySelectorAll('.sp-smart-post-wrapper').forEach((container) => {
978		/**
979		 * Preloader.
980		 * Fades out preloader.
981		 */
982		const preloader = container?.querySelector(
983			'.sp-smart-post-show-pro-pre-query .sp-smart-post-preloader'
984		);
985
986		if (preloader) {
987			// Wait 2.5 seconds before showing fallback.
988			setTimeout(() => {
989				preloader.classList.remove('sp-d-block');
990				preloader.classList.add('sp-d-hidden');
991				container.classList.add('sp-smart-preloader-removed');
992			}, 500);
993		}
994		// Social Links Copy notification.
995		const socialCopyLinks = container.querySelectorAll(
996			'.sp-copy-url-area .sp-smart-post-copy-btn'
997		);
998		if (socialCopyLinks.length > 0) {
999			let classText;
1000			socialCopyLinks.forEach((socialCopyLink) => {
1001				socialCopyLink.addEventListener('click', (e) => {
1002					const copyText = socialCopyLink.querySelector(
1003						'.sp-post-url-copy-popup'
1004					);
1005					// e.preventDefault();
1006					copyText.classList.remove('sp-d-hidden');
1007					copyText.classList.add('sp-d-block');
1008					clearTimeout(classText);
1009					classText = setTimeout(() => {
1010						copyText.classList.remove('sp-d-block');
1011						copyText.classList.add('sp-d-hidden');
1012					}, 2000);
1013				});
1014			});
1015		}
1016		if (
1017			container?.classList.contains('sp-smart-post-thumbnail-slider') ||
1018			container?.classList.contains(
1019				'sp-smart-post-thumbnail-slider-two'
1020			) ||
1021			container?.classList.contains('sp-smart-thumbnail-slider-two')
1022		) {
1023			return false;
1024		}
1025
1026		// Closest parent block with specific block class.
1027		const blockParent = container.closest(
1028			'.wp-block-sp-smart-post-show-smart-post-parent'
1029		);
1030
1031		const blockId = container.dataset.blockid;
1032		const page_id = container.dataset.pageid || '';
1033		const block_location = container.dataset.location || '';
1034
1035		if (blockParent && selected_params?.block === blockId) {
1036			updateSelectByParams(selected_params, blockParent);
1037		}
1038		/**
1039		 * SECTION 1: INIT SWIPER OR MARQUEE SLIDERS
1040		 */
1041		const containerEl = container.querySelector(
1042			'.layout-standard, .layout-center, .swiper-container, .sp_marquee-container'
1043		);
1044
1045		let sps_swiper = null;
1046		let sps_swiper_option = {};
1047		let sps_marquee = null;
1048		let sps_marquee_option = {};
1049
1050		// Initialize Swiper slider if present
1051		if (containerEl?.classList.contains('swiper-container')) {
1052			const options = safeJSONParse(
1053				containerEl.getAttribute('data-swiper-options')?.replace(/u0022/g, '"')
1054			);
1055
1056			if (!Object.keys(options).length) {
1057				return;
1058			}
1059			const paginationOptions = options?.pagination;
1060			const paginationClassName = paginationOptions?.el;
1061			const isNumberPagination = !!options.pagination?.paginationType;
1062			sps_swiper_option = {
1063				...options,
1064				pagination: isNumberPagination
1065					? paginationDotNumber(paginationClassName)
1066					: paginationOptions,
1067			};
1068
1069			if (
1070				sps_swiper_option.effect &&
1071				['fade', 'cube', 'flip'].includes(sps_swiper_option?.effect)
1072			) {
1073				wrapSlidesForEffect(containerEl, sps_swiper_option);
1074			}
1075
1076			sps_swiper = new PCPSwiper(containerEl, sps_swiper_option);
1077		}
1078
1079		// Initialize Marquee slider if present
1080		if (containerEl?.classList.contains('sp_marquee-container')) {
1081			sps_marquee_option = safeJSONParse(
1082				containerEl.getAttribute('data-options')
1083			);
1084			if (!Object.keys(sps_marquee_option).length) {
1085				return;
1086			}
1087			sps_marquee_option = {
1088				speed: sps_marquee_option.speed || 500,
1089				direction:
1090					sps_marquee_option.direction === 'left_to_right'
1091						? 'right'
1092						: 'left',
1093				pauseOnHover: sps_marquee_option.pauseOnHover !== false,
1094				slidesPerView: sps_marquee_option.slidesPerView || 1,
1095				slidesPerViewMobile:
1096					sps_marquee_option.slidesPerViewMobile || 1,
1097				slidesPerViewTablet:
1098					sps_marquee_option.slidesPerViewTablet || 1,
1099				spaceBetween: sps_marquee_option.spaceBetween || 0,
1100				spaceBetweenMobile: sps_marquee_option.spaceBetweenMobile || 0,
1101				spaceBetweenTablet: sps_marquee_option.spaceBetweenTablet || 0,
1102			};
1103			sps_marquee = new SP_Marquee(containerEl, sps_marquee_option);
1104		}
1105
1106		/**
1107		 * SECTION 2: FILTER HANDLING
1108		 */
1109
1110		// let sps_date = selected_params['sps_date']
1111		// 	? selected_params['sps_date']
1112		// 	: '';
1113		// let sps_preset_date = selected_params['sps_preset_date']
1114		// 	? selected_params['sps_preset_date']
1115		// 	: '';
1116		let sps_date;
1117		let sps_preset_date;
1118
1119		const filter_fields =
1120			blockParent?.querySelectorAll(
1121				'.sp-smart-post-live-filter-parent select[name], .sp-smart-post-live-filter-parent input[name]'
1122			) || [];
1123
1124		const filter_relation =
1125			blockParent?.querySelector('.sp-smart-post-live-filter-parent')
1126				?.dataset.relation || 'and';
1127
1128		// Fetch filtered content.
1129		const loadQueryData = (state) => {
1130			state.block_location = block_location;
1131			
1132			return fetch(sp_smart_post_block_localize.restUrl, {
1133				method: 'POST',
1134				headers: { 'Content-Type': 'application/json' },
1135				body: JSON.stringify(state),
1136			}).then((res) => res.json());
1137		};
1138
1139		function updateURLQuery(customParams) {
1140			const baseUrl = new URL(
1141				sp_smart_post_block_localize.permalink_structure ||
1142					window.location.href
1143			);
1144
1145			// START FROM EXISTING URL PARAMS
1146			const params = new URLSearchParams(baseUrl.search);
1147
1148			const allowedKeys = [
1149				'page_id',
1150				'block',
1151				'tx_category',
1152				'sps_date',
1153				'sps_preset_date',
1154				'sps_sort',
1155				'sps_search',
1156				'sps_page',
1157			];
1158
1159			// Always ensure block
1160			if (blockId) {
1161				params.set('block', blockId);
1162			}
1163
1164			Object.entries(customParams).forEach(([key, value]) => {
1165				if (!allowedKeys.includes(key)) return;
1166
1167				if (value !== '' && value !== null && value !== undefined) {
1168					params.set(key, value);
1169				} else {
1170					params.delete(key);
1171				}
1172			});
1173
1174			// Cleanup unknown params
1175			[...params.keys()].forEach((key) => {
1176				if (!allowedKeys.includes(key)) {
1177					params.delete(key);
1178				}
1179			});
1180
1181			baseUrl.search = params.toString();
1182			window.history.replaceState({}, '', baseUrl.toString());
1183		}
1184
1185		// Build filter state object.
1186		function getFilterState(
1187			event,
1188			update_url = true,
1189			pagination_section = null
1190		) {
1191			const state = {};
1192			const currentField = event?.target || null;
1193			pagination_section =
1194				pagination_section ??
1195				currentField?.closest('.sp-smart-post-pagination-section');
1196			if (
1197				pagination_section &&
1198				'pagination' == pagination_section?.dataset.paginationtype &&
1199				currentField.tagName === 'A'
1200			) {
1201				const currentPage = parseInt(
1202					pagination_section.dataset.current,
1203					10
1204				);
1205				newPage = 1;
1206				if (currentField.classList.contains('prev')) {
1207					newPage = currentPage - 1;
1208				} else if (currentField.classList.contains('next')) {
1209					newPage = currentPage + 1;
1210				} else {
1211					newPage = parseInt(currentField.dataset.page, 10);
1212				}
1213				if (newPage > 1) {
1214					state.sps_page = newPage || 1;
1215				}
1216			}
1217			filter_fields.forEach((field) => {
1218				// 	if (pagination_section && field.tagName === 'DIV') {
1219				// 		if (field.dataset.current > 1) {
1220				// 			state['page'] = field.dataset.current || 1;
1221				// 		}
1222				// 	} else {
1223
1224				let key = field.name;
1225				const value = field.value.trim();
1226				if (key === 'blog_search') {
1227					key = 'search';
1228				}
1229
1230				state['sps_preset_date'] = sps_preset_date
1231					? sps_preset_date
1232					: '';
1233				state['sps_date'] = sps_date ? sps_date : '';
1234				state[key] = value;
1235
1236				//	}
1237			});
1238
1239			if (update_url) {
1240				updateURLQuery(state);
1241			}
1242			if (Object.keys(state).length > 0) {
1243				state.block = blockId;
1244				state.page_id = page_id;
1245				state.relation = filter_relation;
1246			}
1247
1248			return state;
1249		}
1250
1251		// Initial count load
1252		let currentState = getFilterState(null, false);
1253
1254		function debounce(fn, delay) {
1255			let timer;
1256			return function (...args) {
1257				clearTimeout(timer);
1258				timer = setTimeout(() => fn.apply(this, args), delay);
1259			};
1260		}
1261		const pagination_section = container.querySelector(
1262			'.sp-smart-post-pagination-section'
1263		);
1264		// Load More
1265		const loadMoreWrapper = pagination_section?.querySelector(
1266			'.sp-smart-post-load-more-button'
1267		);
1268
1269		let fromDate;
1270		let toDate;
1271		function datePicker() {
1272			blockParent
1273				.querySelectorAll('[sps-date-filter-calendar]')
1274				.forEach((calendar) => {
1275					const currentDate = new Date();
1276					const defaultDate = selected_params['sps_date'];
1277
1278					// If sps_date exists, make the date as default.
1279					if (defaultDate && defaultDate.startsWith('from-')) {
1280						const match = defaultDate.match(
1281							/from-(\d{2})-(\d{2})-(\d{4})-to-(\d{2})-(\d{2})-(\d{4})/
1282						);
1283
1284						if (match) {
1285							fromDate = new Date(
1286								match[3],
1287								match[2] - 1,
1288								match[1]
1289							);
1290							toDate = new Date(match[6], match[5] - 1, match[4]);
1291						}
1292					}
1293
1294					const monthNames = [
1295						'January',
1296						'February',
1297						'March',
1298						'April',
1299						'May',
1300						'June',
1301						'July',
1302						'August',
1303						'September',
1304						'October',
1305						'November',
1306						'December',
1307					];
1308
1309					const grid = calendar.querySelector(
1310						'.sps-smart-post-date-filter-calendar-grid'
1311					);
1312					const monthLabel = calendar.querySelector(
1313						'.sps-date-filter-month-label'
1314					);
1315					const yearLabel = calendar.querySelector(
1316						'.sps-date-filter-year-label'
1317					);
1318					const monthList = calendar.querySelector(
1319						'.sps-date-filter-month-list'
1320					);
1321
1322					const yearList = calendar.querySelector(
1323						'.sps-date-filter-year-list'
1324					);
1325
1326					if (!grid || !monthLabel || !yearLabel) return;
1327
1328					// ---------- Helpers ----------
1329					const daysInMonth = (date) =>
1330						new Date(
1331							date.getFullYear(),
1332							date.getMonth() + 1,
1333							0
1334						).getDate();
1335
1336					const firstDayOfMonth = (date) =>
1337						new Date(
1338							date.getFullYear(),
1339							date.getMonth(),
1340							1
1341						).getDay();
1342
1343					const formatDate = (date) => {
1344						if (!date) return '';
1345						return `${String(date.getDate()).padStart(2, '0')}-${String(
1346							date.getMonth() + 1
1347						).padStart(2, '0')}-${date.getFullYear()}`;
1348					};
1349
1350					const sameDate = (d1, d2) =>
1351						d1 &&
1352						d2 &&
1353						d1.getDate() === d2.getDate() &&
1354						d1.getMonth() === d2.getMonth() &&
1355						d1.getFullYear() === d2.getFullYear();
1356
1357					const inRange = (date) =>
1358						fromDate && toDate && date > fromDate && date < toDate;
1359
1360					// ---------- Render ----------
1361					function renderCalendar() {
1362						grid.innerHTML = '';
1363						monthLabel.textContent =
1364							monthNames[currentDate.getMonth()];
1365						yearLabel.textContent = currentDate.getFullYear();
1366
1367						const days = [];
1368						const prevMonthDays = new Date(
1369							currentDate.getFullYear(),
1370							currentDate.getMonth(),
1371							0
1372						).getDate();
1373
1374						const firstDay = firstDayOfMonth(currentDate);
1375
1376						for (
1377							let i = prevMonthDays - firstDay + 1;
1378							i <= prevMonthDays;
1379							i++
1380						) {
1381							days.push({ day: i, current: false });
1382						}
1383
1384						for (let i = 1; i <= daysInMonth(currentDate); i++) {
1385							days.push({ day: i, current: true });
1386						}
1387
1388						let nextMonthDay = 1;
1389						while (days.length < 42) {
1390							days.push({
1391								day: nextMonthDay++,
1392								current: false,
1393							});
1394						}
1395
1396						days.forEach((d) => {
1397							const btn = document.createElement('button');
1398							const dateObj = new Date(
1399								currentDate.getFullYear(),
1400								currentDate.getMonth(),
1401								d.day
1402							);
1403
1404							btn.textContent = d.day;
1405							btn.className =
1406								'sps-smart-post-date-filter-calendar-day ' +
1407								(d.current ? 'current-month' : 'other-month');
1408
1409							if (sameDate(dateObj, fromDate))
1410								btn.classList.add('from');
1411							if (sameDate(dateObj, toDate))
1412								btn.classList.add('to');
1413							if (inRange(dateObj)) btn.classList.add('in-range');
1414
1415							btn.addEventListener('click', (e) => {
1416								if (!d.current) return;
1417								e.stopPropagation();
1418
1419								monthList.style.display = 'none';
1420								yearList.style.display = 'none';
1421
1422								if (fromDate && toDate) {
1423									fromDate = dateObj;
1424									toDate = null;
1425									renderCalendar();
1426									return;
1427								}
1428
1429								if (!fromDate) {
1430									fromDate = dateObj;
1431									renderCalendar();
1432									return;
1433								}
1434
1435								if (!toDate) {
1436									if (dateObj < fromDate) {
1437										toDate = fromDate;
1438										fromDate = dateObj;
1439									} else {
1440										toDate = dateObj;
1441									}
1442
1443									renderCalendar();
1444									closeDropdown();
1445								}
1446							});
1447
1448							grid.appendChild(btn);
1449						});
1450					}
1451
1452					//---------- ui ----------
1453					function closeDropdown() {
1454						const dropdown = calendar.closest(
1455							'.sp-smart-post-live-filter-dropdown-date'
1456						);
1457						const button = calendar
1458							.closest('.sp-smart-post-date-filter')
1459							?.querySelector('.sp-smart-post-live-filter-btn');
1460
1461						if (dropdown) dropdown.classList.remove('open');
1462
1463						if (button) {
1464							button.setAttribute('aria-expanded', 'false');
1465							const span = button.querySelector(
1466								'.sp-smart-post-show-date-filter-date-value'
1467							);
1468							if (span) {
1469								span.textContent =
1470									formatDate(fromDate) +
1471									' - ' +
1472									formatDate(toDate);
1473								sps_date =
1474									'from-' +
1475									formatDate(fromDate) +
1476									'-to-' +
1477									formatDate(toDate);
1478
1479								currentState['sps_date'] =
1480									'from-' +
1481									formatDate(fromDate) +
1482									'-to-' +
1483									formatDate(toDate);
1484
1485								updateURLQuery(currentState);
1486								if (preloader) {
1487									// Wait 2.5 seconds before showing fallback
1488									preloader.classList.add('sp-d-block');
1489									container.classList.remove(
1490										'sp-smart-preloader-removed'
1491									);
1492								}
1493								let itemsEl = null;
1494								delete currentState.html;
1495								loadQueryData(currentState).then((data) => {
1496									if (!data.success) {
1497										return;
1498									}
1499
1500									if (pagination_section) {
1501										pagination_section.dataset.current = 1;
1502									}
1503									if (
1504										sps_marquee &&
1505										containerEl.classList.contains(
1506											'sp_marquee-container'
1507										)
1508									) {
1509										container.querySelector(
1510											'.sp_marquee-content'
1511										).innerHTML = data.html;
1512										sps_marquee = new SP_Marquee(
1513											containerEl,
1514											sps_marquee_option
1515										);
1516									} else if (sps_swiper) {
1517										// if (sps_swiper.slides && sps_swiper.slides.length > 0) {
1518										// 	//	sps_swiper.removeAllSlides();
1519										// }
1520
1521										sps_swiper.destroy(true);
1522
1523										container.querySelector(
1524											'.swiper-wrapper'
1525										).innerHTML = data.html;
1526										if (
1527											sps_swiper_option.effect &&
1528											['fade', 'cube', 'flip'].includes(
1529												sps_swiper_option?.effect
1530											)
1531										) {
1532											wrapSlidesForEffect(
1533												containerEl,
1534												sps_swiper_option
1535											);
1536										}
1537										sps_swiper = new PCPSwiper(
1538											containerEl,
1539											sps_swiper_option
1540										);
1541									} else {
1542										const items = container.querySelector(
1543											'.sp-smart-post-items'
1544										);
1545										items.innerHTML = data.html;
1546										itemsEl = items;
1547										// container.querySelector(
1548										// 	'.sp-smart-post-items'
1549										// ).style.opacity = '1';
1550										//  Staggered Animation
1551										if (itemsEl) {
1552											const childItems =
1553												itemsEl.querySelectorAll(
1554													'.sp-smart-post-card, .swiper-slide'
1555												);
1556											childItems.forEach((el, index) => {
1557												el.style.opacity = 0;
1558												el.style.animation = `fadeIn 0.7s ease-in-out forwards`;
1559												el.style.animationDelay = `${index * 0.1}s`; // 80ms stagger
1560											});
1561										}
1562									}
1563									const termCounts = data.count_data;
1564									if (
1565										termCounts &&
1566										hasFilterCounts(termCounts)
1567									) {
1568										updateFilterCounts(
1569											termCounts,
1570											pagination_section,
1571											blockParent
1572										);
1573										updateAllSmartPostFilterCounts(
1574											blockParent
1575										);
1576									} else if (
1577										Object.keys(currentState).length > 0
1578									) {
1579										blockParent
1580											.querySelectorAll(
1581												'.sp-smart-post-taxonomy-filter select option'
1582											)
1583											.forEach((option) => {
1584												const slug = option.value;
1585												if (slug) {
1586													option.textContent = `${capitalize(
1587														slug
1588													)} (0)`;
1589													option.disabled = true;
1590												}
1591											});
1592										Object.entries(termCounts).forEach(
1593											([taxonomy, terms]) => {
1594												// Handle pagination update
1595												if (
1596													taxonomy === 'pagination' &&
1597													pagination_section
1598												) {
1599													updatePaginationData(
1600														pagination_section,
1601														terms
1602													);
1603												}
1604											}
1605										);
1606										updateAllSmartPostFilterCounts(
1607											blockParent
1608										);
1609									} else {
1610										resetFilterCounts(blockParent);
1611									}
1612									socialLinkCopy();
1613									modal();
1614									initTimelineScroll();
1615									initSmartPostFeatures();
1616									if (preloader) {
1617										// Wait 2.5 seconds before showing fallback
1618										setTimeout(() => {
1619											preloader.classList.remove(
1620												'sp-d-block'
1621											);
1622											preloader.classList.add(
1623												'sp-d-hidden'
1624											);
1625											container.classList.add(
1626												'sp-smart-preloader-removed'
1627											);
1628										}, 200);
1629									}
1630									if (loadMoreWrapper) {
1631										const no_more_button =
1632											loadMoreWrapper.querySelector(
1633												'.sps-no-more-post'
1634											);
1635										if (no_more_button) {
1636											const loadMoreWrapperBTN =
1637												loadMoreWrapper.querySelector(
1638													'a'
1639												);
1640											if (loadMoreWrapperBTN) {
1641												loadMoreWrapperBTN.style.display =
1642													'flex';
1643											}
1644											no_more_button.style.display =
1645												'none';
1646										}
1647									}
1648								});
1649							}
1650						}
1651					}
1652
1653					// ---------- Navigation ----------
1654					calendar
1655						.querySelector('.sps-date-filter-nav-prev')
1656						?.addEventListener('click', (e) => {
1657							e.stopPropagation();
1658							currentDate.setMonth(currentDate.getMonth() - 1);
1659							renderCalendar();
1660						});
1661
1662					calendar
1663						.querySelector('.sps-date-filter-nav-next')
1664						?.addEventListener('click', (e) => {
1665							e.stopPropagation();
1666							currentDate.setMonth(currentDate.getMonth() + 1);
1667							renderCalendar();
1668						});
1669					// ---------- Month List ----------
1670					monthNames.forEach((m, i) => {
1671						const btn = document.createElement('button');
1672						btn.textContent = m;
1673						btn.onclick = (e) => {
1674							e.stopPropagation();
1675							currentDate.setMonth(i);
1676							renderCalendar();
1677							monthList.style.display = 'none';
1678						};
1679						monthList.appendChild(btn);
1680					});
1681
1682					// ---------- Year List ----------
1683					const currentYear = new Date().getFullYear();
1684					for (let y = currentYear; y >= 2000; y--) {
1685						const btn = document.createElement('button');
1686						btn.textContent = y;
1687						btn.onclick = (e) => {
1688							e.stopPropagation();
1689							currentDate.setFullYear(y);
1690							renderCalendar();
1691							yearList.style.display = 'none';
1692						};
1693						yearList.appendChild(btn);
1694					}
1695
1696					// ---------- Toggles ----------
1697					const monthTrigger = calendar.querySelector(
1698						'.sps-date-filter-month-trigger'
1699					);
1700					if (monthTrigger && !monthTrigger.dataset.bound) {
1701						monthTrigger.dataset.bound = 'true';
1702						monthTrigger.addEventListener('click', (e) => {
1703							e.stopPropagation();
1704							monthList.style.display =
1705								monthList.style.display === 'block'
1706									? 'none'
1707									: 'block';
1708							yearList.style.display = 'none';
1709						});
1710					}
1711
1712					const yearTrigger = calendar.querySelector(
1713						'.sps-date-filter-year-trigger'
1714					);
1715					if (yearTrigger && !yearTrigger.dataset.bound) {
1716						yearTrigger.dataset.bound = 'true';
1717						yearTrigger?.addEventListener('click', (e) => {
1718							e.stopPropagation();
1719							yearList.style.display =
1720								yearList.style.display === 'block'
1721									? 'none'
1722									: 'block';
1723							monthList.style.display = 'none';
1724						});
1725					}
1726
1727					document.addEventListener('click', (e) => {
1728						if (!calendar.contains(e.target)) {
1729							monthList.style.display = 'none';
1730							yearList.style.display = 'none';
1731						}
1732					});
1733
1734					renderCalendar();
1735				});
1736		}
1737
1738		function datePreset() {
1739			const dateilter = blockParent.querySelector(
1740				'.sp-smart-post-date-filter-main'
1741			);
1742			if (dateilter) {
1743				dateilter.querySelectorAll('a[data-value]').forEach((link) => {
1744					const dropdown = blockParent.querySelector(
1745						'.sp-smart-post-live-filter-dropdown-date, .sp-smart-post-live-filter-button-date'
1746					);
1747
1748					const presetType = dropdown.dataset.presetType;
1749
1750					const button = blockParent.querySelector(
1751						'.sp-smart-post-date-filter > .sp-smart-post-live-filter-btn'
1752					);
1753
1754					link.addEventListener('click', function (e) {
1755						e.preventDefault();
1756						blockParent
1757							.querySelectorAll('a[data-value]')
1758							.forEach((l) => l.classList.remove('active'));
1759
1760						this.classList.add('active');
1761
1762						if (presetType === 'dropdown') {
1763							const label = button.querySelector(
1764								'.sp-smart-post-show-date-filter-date-value'
1765							);
1766
1767							if (label) label.textContent = this.textContent;
1768
1769							dropdown.classList.remove('open');
1770							button.setAttribute('aria-expanded', 'false');
1771						}
1772
1773						sps_preset_date = this.dataset.value;
1774						currentState['sps_preset_date'] = sps_preset_date;
1775
1776						updateURLQuery(currentState);
1777
1778						if (preloader) {
1779							// Wait 2.5 seconds before showing fallback
1780							preloader.classList.add('sp-d-block');
1781							container.classList.remove(
1782								'sp-smart-preloader-removed'
1783							);
1784						}
1785						let itemsEl = null;
1786						delete currentState.html;
1787						loadQueryData(currentState).then((data) => {
1788							if (!data.success) {
1789								return;
1790							}
1791
1792							if (pagination_section) {
1793								pagination_section.dataset.current = 1;
1794							}
1795							if (
1796								sps_marquee &&
1797								containerEl.classList.contains(
1798									'sp_marquee-container'
1799								)
1800							) {
1801								container.querySelector(
1802									'.sp_marquee-content'
1803								).innerHTML = data.html;
1804								sps_marquee = new SP_Marquee(
1805									containerEl,
1806									sps_marquee_option
1807								);
1808							} else if (sps_swiper) {
1809								// if (sps_swiper.slides && sps_swiper.slides.length > 0) {
1810								// 	//	sps_swiper.removeAllSlides();
1811								// }
1812								sps_swiper.destroy(true);
1813								container.querySelector(
1814									'.swiper-wrapper'
1815								).innerHTML = data.html;
1816								if (
1817									sps_swiper_option.effect &&
1818									['fade', 'cube', 'flip'].includes(
1819										sps_swiper_option?.effect
1820									)
1821								) {
1822									wrapSlidesForEffect(
1823										containerEl,
1824										sps_swiper_option
1825									);
1826								}
1827								sps_swiper = new PCPSwiper(
1828									containerEl,
1829									sps_swiper_option
1830								);
1831							} else {
1832								const items = container.querySelector(
1833									'.sp-smart-post-items'
1834								);
1835								items.innerHTML = data.html;
1836								itemsEl = items;
1837								if (itemsEl) {
1838									const childItems = itemsEl.querySelectorAll(
1839										'.sp-smart-post-card, .swiper-slide'
1840									);
1841									childItems.forEach((el, index) => {
1842										el.style.opacity = 0;
1843										el.style.animation = `fadeIn 0.7s ease-in-out forwards`;
1844										el.style.animationDelay = `${index * 0.1}s`; // 80ms stagger
1845									});
1846								}
1847							}
1848							const termCounts = data.count_data;
1849							if (termCounts && hasFilterCounts(termCounts)) {
1850								updateFilterCounts(
1851									termCounts,
1852									pagination_section,
1853									blockParent
1854								);
1855								updateAllSmartPostFilterCounts(blockParent);
1856							} else if (Object.keys(currentState).length > 0) {
1857								blockParent
1858									.querySelectorAll(
1859										'.sp-smart-post-taxonomy-filter select option'
1860									)
1861									.forEach((option) => {
1862										const slug = option.value;
1863										if (slug) {
1864											option.textContent = `${capitalize(
1865												slug
1866											)} (0)`;
1867											option.disabled = true;
1868										}
1869									});
1870								Object.entries(termCounts).forEach(
1871									([taxonomy, terms]) => {
1872										// Handle pagination update
1873										if (
1874											taxonomy === 'pagination' &&
1875											pagination_section
1876										) {
1877											updatePaginationData(
1878												pagination_section,
1879												terms
1880											);
1881										}
1882									}
1883								);
1884								updateAllSmartPostFilterCounts(blockParent);
1885							} else {
1886								resetFilterCounts(blockParent);
1887							}
1888							socialLinkCopy();
1889							modal();
1890							initTimelineScroll();
1891							initSmartPostFeatures();
1892							if (preloader) {
1893								// Wait 2.5 seconds before showing fallback
1894								setTimeout(() => {
1895									preloader.classList.remove('sp-d-block');
1896									preloader.classList.add('sp-d-hidden');
1897									container.classList.add(
1898										'sp-smart-preloader-removed'
1899									);
1900								}, 200);
1901							}
1902							if (loadMoreWrapper) {
1903								const no_more_button =
1904									loadMoreWrapper.querySelector(
1905										'.sps-no-more-post'
1906									);
1907								if (no_more_button) {
1908									const loadMoreWrapperBTN =
1909										loadMoreWrapper.querySelector('a');
1910									if (loadMoreWrapperBTN) {
1911										loadMoreWrapperBTN.style.display =
1912											'flex';
1913									}
1914									no_more_button.style.display = 'none';
1915								}
1916							}
1917						});
1918					});
1919				});
1920			}
1921		}
1922
1923		function resetTaxonomyFilter() {
1924			const taxonomyEl = blockParent.querySelector(
1925				'.sp-smart-post-taxonomy-filter'
1926			);
1927
1928			if (!taxonomyEl) {
1929				return;
1930			}
1931
1932			//  Reset button text
1933			const allText = taxonomyEl.dataset.allText || 'All';
1934
1935			const btnTextEl = taxonomyEl.querySelector(
1936				'.sp-smart-post-live-filter-btn span'
1937			);
1938
1939			if (btnTextEl) {
1940				btnTextEl.textContent = allText;
1941			}
1942
1943			// Reset active state
1944			const links = taxonomyEl.querySelectorAll(
1945				'.sps-live-filter-nav-link'
1946			);
1947
1948			links.forEach((link) => {
1949				link.classList.remove('active');
1950				link.removeAttribute('aria-current');
1951			});
1952
1953			// Activate default ("All")
1954			const allLink = taxonomyEl.querySelector(
1955				'.sps-live-filter-nav-link[data-value=""]'
1956			);
1957
1958			if (allLink) {
1959				allLink.classList.add('active');
1960				allLink.setAttribute('aria-current', 'true');
1961			}
1962
1963			// Reset hidden select (if exists)
1964			const select = taxonomyEl.querySelector('select');
1965			if (select) {
1966				select.value = '';
1967			}
1968		}
1969
1970		function resetSortFilter() {
1971			const sortEl = blockParent.querySelector(
1972				'.sp-smart-post-sort-filter'
1973			);
1974
1975			if (!sortEl) {
1976				return;
1977			}
1978
1979			//  Reset button text
1980			const placeholder = sortEl.dataset.sortPlaceholder || 'None';
1981
1982			const btnTextEl = sortEl.querySelector(
1983				'.sp-smart-post-live-filter-btn span'
1984			);
1985
1986			if (btnTextEl) {
1987				btnTextEl.textContent = placeholder;
1988			}
1989
1990			//  Reset active items
1991			const links = sortEl.querySelectorAll('.sps-live-filter-nav-link');
1992
1993			links.forEach((link) => {
1994				link.classList.remove('active');
1995				link.removeAttribute('aria-current');
1996			});
1997
1998			// Activate "None"
1999
2000			const noneLink = sortEl.querySelector(
2001				'.sps-live-filter-nav-link[data-value=""]'
2002			);
2003
2004			if (noneLink) {
2005				noneLink.classList.add('active');
2006				noneLink.setAttribute('aria-current', 'true');
2007			}
2008
2009			// Sync hidden select (IMPORTANT)
2010			const select = sortEl.querySelector('select[name="sps_sort"]');
2011			if (select) {
2012				select.value = '';
2013			}
2014		}
2015
2016		function resetDateFilter() {
2017			const dateFilterEl = blockParent.querySelector(
2018				'.sp-smart-post-date-filter'
2019			);
2020
2021			if (!dateFilterEl) {
2022				return;
2023			}
2024
2025			// Reset button text
2026			const button = dateFilterEl.querySelector(
2027				'.sp-smart-post-live-filter-btn'
2028			);
2029
2030			if (button) {
2031				const label = button.querySelector(
2032					'.sp-smart-post-show-date-filter-date-value'
2033				);
2034				const defaultLabel = label.dataset.defaultLabel || 'Select';
2035				if (label) label.textContent = defaultLabel;
2036			}
2037
2038			// Reset active state in dropdown
2039			const links = dateFilterEl.querySelectorAll('a[data-value]');
2040			links.forEach((link) => {
2041				link.classList.remove('active');
2042				link.removeAttribute('aria-current');
2043			});
2044
2045			// Activate default (empty value or first item)
2046			const defaultLink = dateFilterEl.querySelector('a[data-value=""]');
2047			if (defaultLink) {
2048				defaultLink.classList.add('active');
2049				defaultLink.setAttribute('aria-current', 'true');
2050			}
2051
2052			// Reset global state
2053			currentState.sps_preset_date = '';
2054			sps_preset_date = '';
2055			fromDate = null;
2056			toDate = null;
2057			datePicker();
2058		}
2059
2060		function clearFilter() {
2061			const clearFilterWrapper = blockParent.querySelectorAll(
2062				'.sp-smart-post-clear-filter-main'
2063			);
2064
2065			clearFilterWrapper.forEach((wrapper) => {
2066				wrapper.addEventListener('click', async (e) => {
2067					e.preventDefault();
2068
2069					// RESET GLOBAL FILTER STATE
2070					currentState = {
2071						block: blockId,
2072						block_location,
2073						page_id,
2074						relation: filter_relation,
2075						sps_search: '',
2076						sps_sort: '',
2077						tx_category: '',
2078					};
2079
2080					// Reset globals
2081					sps_date = '';
2082					sps_preset_date = '';
2083
2084					// RESET UI
2085					resetTaxonomyFilter();
2086					resetSortFilter();
2087					resetDateFilter();
2088
2089					const searchInput = blockParent.querySelector(
2090						'.sp-smart-post-search-field > input'
2091					);
2092					if (searchInput) searchInput.value = '';
2093
2094					// UPDATE URL (ONCE)
2095					updateURLQuery(currentState);
2096
2097					// SHOW PRELOADER
2098					if (preloader) {
2099						preloader.classList.add('sp-d-block');
2100						container.classList.remove(
2101							'sp-smart-preloader-removed'
2102						);
2103					}
2104
2105					const data = await loadQueryData(currentState);
2106					if (!data?.success) return;
2107
2108					// RESET PAGINATION
2109					if (pagination_section) {
2110						pagination_section.dataset.current = 1;
2111					}
2112
2113					// RENDER CONTENT
2114					if (
2115						sps_marquee &&
2116						containerEl.classList.contains('sp_marquee-container')
2117					) {
2118						container.querySelector(
2119							'.sp_marquee-content'
2120						).innerHTML = data.html;
2121						sps_marquee = new SP_Marquee(
2122							containerEl,
2123							sps_marquee_option
2124						);
2125					} else if (sps_swiper) {
2126						sps_swiper.destroy(true);
2127						container.querySelector('.swiper-wrapper').innerHTML =
2128							data.html;
2129
2130						if (
2131							['fade', 'cube', 'flip'].includes(
2132								sps_swiper_option?.effect
2133							)
2134						) {
2135							wrapSlidesForEffect(containerEl, sps_swiper_option);
2136						}
2137
2138						sps_swiper = new PCPSwiper(
2139							containerEl,
2140							sps_swiper_option
2141						);
2142					} else {
2143						const items = container.querySelector(
2144							'.sp-smart-post-items'
2145						);
2146						items.innerHTML = data.html;
2147
2148						items
2149							.querySelectorAll(
2150								'.sp-smart-post-card, .swiper-slide'
2151							)
2152							.forEach((el, index) => {
2153								el.style.opacity = 0;
2154								el.style.animation =
2155									'fadeIn 0.7s ease-in-out forwards';
2156								el.style.animationDelay = `${index * 0.1}s`;
2157							});
2158					}
2159
2160					//  UPDATE COUNTS
2161					if (data.count_data && hasFilterCounts(data.count_data)) {
2162						updateFilterCounts(
2163							data.count_data,
2164							pagination_section,
2165							blockParent
2166						);
2167						updateAllSmartPostFilterCounts(blockParent);
2168					} else {
2169						resetFilterCounts(blockParent);
2170					}
2171
2172					// RE-INIT HELPERS
2173					socialLinkCopy();
2174					modal();
2175					initTimelineScroll();
2176					initSmartPostFeatures();
2177
2178					//  HIDE PRELOADER
2179					if (preloader) {
2180						setTimeout(() => {
2181							preloader.classList.remove('sp-d-block');
2182							preloader.classList.add('sp-d-hidden');
2183							container.classList.add(
2184								'sp-smart-preloader-removed'
2185							);
2186						}, 200);
2187					}
2188
2189					// RESET LOAD MORE
2190					if (loadMoreWrapper) {
2191						const noMoreBtn =
2192							loadMoreWrapper.querySelector('.sps-no-more-post');
2193						const loadMoreBtn = loadMoreWrapper.querySelector('a');
2194
2195						if (loadMoreBtn) loadMoreBtn.style.display = 'flex';
2196						if (noMoreBtn) noMoreBtn.style.display = 'none';
2197					}
2198				});
2199			});
2200		}
2201
2202		// Listen to filter field changes
2203		if (page_id && filter_fields.length > 0) {
2204			currentState.html = false;
2205
2206			loadQueryData(currentState)
2207				.then((data) => {
2208					if (!data.success) {
2209						return;
2210					}
2211					const termCounts = data.count_data;
2212					if (termCounts && hasFilterCounts(termCounts)) {
2213						updateFilterCounts(termCounts, false, blockParent);
2214						updateAllSmartPostFilterCounts(blockParent);
2215					} else if (Object.keys(currentState).length > 0) {
2216						blockParent
2217							.querySelectorAll(
2218								'.sp-smart-filter-area select option'
2219							)
2220							.forEach((option) => {
2221								const slug = option.value;
2222								if (slug) {
2223									option.textContent = `${capitalize(
2224										slug
2225									)} (0)`;
2226									option.disabled = true;
2227								}
2228							});
2229					} else {
2230						resetFilterCounts(blockParent);
2231					}
2232					initTimelineScroll();
2233				})
2234				.catch();
2235			const eventHandler = (e) => {
2236				currentState = getFilterState(e);
2237				if (preloader) {
2238					// Wait 2.5 seconds before showing fallback
2239					preloader.classList.add('sp-d-block');
2240					container.classList.remove('sp-smart-preloader-removed');
2241				}
2242				let itemsEl = null;
2243
2244				loadQueryData(currentState).then((data) => {
2245					if (!data.success) {
2246						return;
2247					}
2248
2249					if (pagination_section) {
2250						pagination_section.dataset.current = 1;
2251					}
2252					if (
2253						sps_marquee &&
2254						containerEl.classList.contains('sp_marquee-container')
2255					) {
2256						container.querySelector(
2257							'.sp_marquee-content'
2258						).innerHTML = data.html;
2259						sps_marquee = new SP_Marquee(
2260							containerEl,
2261							sps_marquee_option
2262						);
2263					} else if (sps_swiper) {
2264						// if (sps_swiper.slides && sps_swiper.slides.length > 0) {
2265						// 	//	sps_swiper.removeAllSlides();
2266						// }
2267
2268						sps_swiper.destroy(true);
2269						container.querySelector('.swiper-wrapper').innerHTML =
2270							data.html;
2271						if (
2272							sps_swiper_option.effect &&
2273							['fade', 'cube', 'flip'].includes(
2274								sps_swiper_option?.effect
2275							)
2276						) {
2277							wrapSlidesForEffect(containerEl, sps_swiper_option);
2278						}
2279						sps_swiper = new PCPSwiper(
2280							containerEl,
2281							sps_swiper_option
2282						);
2283					} else {
2284						const items = container.querySelector(
2285							'.sp-smart-post-items'
2286						);
2287						items.innerHTML = data.html;
2288						itemsEl = items;
2289						// container.querySelector(
2290						// 	'.sp-smart-post-items'
2291						// ).style.opacity = '1';
2292						//  Staggered Animation
2293						if (itemsEl) {
2294							const childItems = itemsEl.querySelectorAll(
2295								'.sp-smart-post-card, .swiper-slide'
2296							);
2297							childItems.forEach((el, index) => {
2298								el.style.opacity = 0;
2299								el.style.animation = `fadeIn 0.7s ease-in-out forwards`;
2300								el.style.animationDelay = `${index * 0.1}s`; // 80ms stagger
2301							});
2302						}
2303					}
2304					const termCounts = data.count_data;
2305					if (termCounts && hasFilterCounts(termCounts)) {
2306						updateFilterCounts(
2307							termCounts,
2308							pagination_section,
2309							blockParent
2310						);
2311						updateAllSmartPostFilterCounts(blockParent);
2312					} else if (Object.keys(currentState).length > 0) {
2313						blockParent
2314							.querySelectorAll(
2315								'.sp-smart-post-taxonomy-filter select option'
2316							)
2317							.forEach((option) => {
2318								const slug = option.value;
2319								if (slug) {
2320									option.textContent = `${capitalize(
2321										slug
2322									)} (0)`;
2323									option.disabled = true;
2324								}
2325							});
2326						Object.entries(termCounts).forEach(
2327							([taxonomy, terms]) => {
2328								// Handle pagination update
2329								if (
2330									taxonomy === 'pagination' &&
2331									pagination_section
2332								) {
2333									updatePaginationData(
2334										pagination_section,
2335										terms
2336									);
2337								}
2338							}
2339						);
2340						updateAllSmartPostFilterCounts(blockParent);
2341					} else {
2342						resetFilterCounts(blockParent);
2343					}
2344					socialLinkCopy();
2345					modal();
2346					initTimelineScroll();
2347					initSmartPostFeatures();
2348					if (preloader) {
2349						// Wait 2.5 seconds before showing fallback
2350						setTimeout(() => {
2351							preloader.classList.remove('sp-d-block');
2352							preloader.classList.add('sp-d-hidden');
2353							container.classList.add(
2354								'sp-smart-preloader-removed'
2355							);
2356						}, 200);
2357					}
2358					if (loadMoreWrapper) {
2359						const no_more_button =
2360							loadMoreWrapper.querySelector('.sps-no-more-post');
2361						if (no_more_button) {
2362							const loadMoreWrapperBTN =
2363								loadMoreWrapper.querySelector('a');
2364							if (loadMoreWrapperBTN) {
2365								loadMoreWrapperBTN.style.display = 'flex';
2366							}
2367							no_more_button.style.display = 'none';
2368						}
2369					}
2370				});
2371			};
2372			filter_fields.forEach((field) => {
2373				const isInput = field.tagName === 'INPUT';
2374				const eventName = isInput ? 'input' : 'change';
2375
2376				// Add event listener.
2377				field.addEventListener(
2378					eventName,
2379					isInput ? debounce(eventHandler, 400) : eventHandler
2380				);
2381			});
2382			datePreset();
2383			datePicker();
2384			clearFilter();
2385		}
2386
2387		function dateFilterToggle() {
2388
2389			const mainFilters = blockParent
2390				?.querySelectorAll('.sp-smart-post-date-filter-main');
2391			
2392				mainFilters?.forEach((wrapper) => {
2393					const button = wrapper.querySelector(
2394						'.sp-smart-post-live-filter-btn'
2395					);
2396					const dropdown = wrapper.querySelector(
2397						'.sp-smart-post-live-filter-dropdown-date'
2398					);
2399					if (!button || !dropdown) return;
2400					// Toggle dropdown
2401					button.addEventListener('click', function (e) {
2402						e.preventDefault();
2403						e.stopPropagation();
2404						dropdown.classList.toggle('open');
2405						button.setAttribute(
2406							'aria-expanded',
2407							dropdown.classList.contains('open')
2408								? 'true'
2409								: 'false'
2410						);
2411					});
2412					// Close on outside click
2413					document.addEventListener('click', function (e) {
2414						if (!wrapper.contains(e.target)) {
2415							dropdown.classList.remove('open');
2416							button.setAttribute('aria-expanded', 'false');
2417						}
2418					});
2419				});
2420		}
2421
2422		dateFilterToggle();
2423		/**
2424		 * SECTION 3: PAGINATION HANDLING
2425		 */
2426
2427		if (!pagination_section) {
2428			return;
2429		}
2430		let current = parseInt(pagination_section.dataset.current, 10);
2431		let total = parseInt(pagination_section.dataset.pages, 10);
2432		const endMessage = pagination_section.dataset.endmessage ?? '';
2433		const pagination_type = pagination_section.dataset.paginationtype;
2434		let contents = container.querySelector(
2435			pagination_type === 'load-more'
2436				? '.sp-smart-post-dynamic-grid-contents,.sp-smart-post-grid-five-static-contents,.sp-smart-post-grid-six-dynamic-contents,.sp-smart-post-timeline-container,.sp-smart-post-small-items,.sp-smart-post-list-one-container'
2437				: '.sp-smart-post-items,.sp-smart-post-list-item'
2438		);
2439
2440		const updateCurrent = (newPage) => {
2441			pagination_section.dataset.current = newPage;
2442			current = newPage;
2443		};
2444		const appendHtml = (html) => {
2445			contents.insertAdjacentHTML('beforeend', html);
2446			return contents;
2447		};
2448
2449		const replaceHtml = (html) => {
2450			contents.innerHTML = html;
2451			return contents;
2452		};
2453
2454		const loadPage = (page, mode = 'replace', currentState = {}) => {
2455			total = parseInt(pagination_section.dataset.pages, 10);
2456			if (page < 1 || page > total || page === current) {
2457				return;
2458			}
2459			contents = container.querySelector(
2460				pagination_type === 'load-more'
2461					? '.sp-smart-post-dynamic-grid-contents,.sp-smart-post-grid-five-static-contents,.sp-smart-post-grid-six-dynamic-contents,.sp-smart-post-timeline-container,.sp-smart-post-small-items,.sp-smart-post-list-one-container'
2462					: '.sp-smart-post-items,.sp-smart-post-list-item'
2463			);
2464			currentState = {
2465				...currentState,
2466				sps_page: page,
2467				pagination_type,
2468				block: blockId,
2469				page_id,
2470			};
2471			const infinitePreloader = pagination_section.querySelector(
2472				'.sp-smart-post-show-preloading'
2473			);
2474			const buttonPreloader = pagination_section.querySelector(
2475				'.sp-smart-post-show-preloader'
2476			);
2477
2478			// Show the correct preloader
2479			if (isInfiniteScroll) {
2480				if (infinitePreloader) {
2481					infinitePreloader.style.display = 'block';
2482				}
2483			} else {
2484				if (buttonPreloader) {
2485					// buttonPreloader.style.display = 'block';
2486					buttonPreloader?.classList?.remove('sp-d-hidden');
2487				}
2488				buttonPreloader?.classList?.add('sp-d-block');
2489			}
2490
2491			loadQueryData(currentState)
2492				.then((data) => {
2493					if (!data.success) {
2494						return;
2495					}
2496					if (mode === 'append') {
2497						// Get items count before append.
2498						const existingCount = contents.querySelectorAll(
2499							'.sp-smart-post-card, .swiper-slide'
2500						).length;
2501						// Append new HTML.
2502						appendHtml(data.html);
2503						// Get all items after append.
2504						const allItems = contents.querySelectorAll(
2505							'.sp-smart-post-card, .swiper-slide'
2506						);
2507						// Animate only the new ones.
2508						allItems.forEach((el, index) => {
2509							if (index >= existingCount) {
2510								el.style.opacity = 0;
2511								el.style.animation = `fadeIn 0.7s ease-in-out forwards`;
2512								el.style.animationDelay = `${
2513									(index - existingCount) * 0.1
2514								}s`;
2515							}
2516						});
2517					} else {
2518						// Replace mode — animate all.
2519						replaceHtml(data.html);
2520						const childItems = contents.querySelectorAll(
2521							'.sp-smart-post-card, .swiper-slide'
2522						);
2523						childItems.forEach((el, index) => {
2524							el.style.opacity = 0;
2525							el.style.animation = `fadeIn 0.7s ease-in-out forwards`;
2526							el.style.animationDelay = `${index * 0.1}s`;
2527						});
2528					}
2529					updateCurrent(page);
2530					updatePaginationUI(pagination_section);
2531					socialLinkCopy();
2532					initSmartPostFeatures();
2533					modal();
2534					initTimelineScroll();
2535					loadMoreWrapper?.classList.remove('sps_disabled');
2536					if (isInfiniteScroll) {
2537						if (infinitePreloader) {
2538							infinitePreloader.style.display = 'none';
2539						}
2540					} else {
2541						if (buttonPreloader) {
2542							// buttonPreloader.style.display = 'none';
2543							buttonPreloader?.classList?.remove('sp-d-block');
2544						}
2545						buttonPreloader?.classList?.add('sp-d-hidden');
2546					}
2547					if (page >= total && loadMoreWrapper) {
2548						loadMoreWrapper.insertAdjacentHTML(
2549							'beforeend',
2550							`<span class="sps-no-more-post">${endMessage}</span>`
2551						);
2552						const loadMoreWrapperBtn =
2553							loadMoreWrapper.querySelector('a');
2554						loadMoreWrapperBtn.style.display = 'none';
2555					}
2556				})
2557				.catch((err) => console.log('Pagination Error:', err));
2558		};
2559
2560		const loadMoreBtn = loadMoreWrapper?.querySelector('a');
2561		const isInfiniteScroll = !!loadMoreWrapper?.querySelector(
2562			'.sp-smart-post-show-preloading'
2563		);
2564
2565		if (isInfiniteScroll && 'IntersectionObserver' in window) {
2566			const observer = new IntersectionObserver(
2567				(entries) => {
2568					if (entries[0].isIntersecting) {
2569						current = parseInt(
2570							pagination_section.dataset.current,
2571							10
2572						);
2573						if (current < total) {
2574							currentState = getFilterState(
2575								null,
2576								true,
2577								pagination_section
2578							);
2579							// Show preloader
2580							const preloader = loadMoreWrapper.querySelector(
2581								'.sp-smart-post-show-preloading'
2582							);
2583							if (preloader) {
2584								preloader.style.display = 'block';
2585							}
2586							loadPage(current + 1, 'append', currentState);
2587						}
2588					}
2589				},
2590				{ rootMargin: '100px' }
2591			);
2592			if (loadMoreWrapper) {
2593				observer.observe(loadMoreWrapper);
2594			}
2595		} else if (loadMoreBtn) {
2596			const load_more_preloader = loadMoreWrapper?.querySelector(
2597				'.sp-smart-post-show-preloader'
2598			);
2599			loadMoreBtn.addEventListener('click', (e) => {
2600				e.preventDefault();
2601				// load_more_preloader.style.display = 'block';
2602				load_more_preloader.classList.remove('sp-d-hidden');
2603				load_more_preloader.classList.add('sp-d-block');
2604				// Disable the button
2605				loadMoreWrapper.classList.add('sps_disabled');
2606
2607				//	loadMoreBtn.textContent = 'Loading...';
2608				current = parseInt(pagination_section.dataset.current, 10);
2609
2610				currentState = getFilterState(e, false);
2611
2612				loadPage(current + 1, 'append', currentState);
2613			});
2614		}
2615		const paginationContainer = pagination_section.querySelector(
2616			'.sp-smart-post-pagination-buttons'
2617		);
2618		paginationContainer?.addEventListener('click', (e) => {
2619			const btn = e.target.closest('.page-numbers');
2620			if (
2621				!btn ||
2622				btn.classList.contains('disabled') ||
2623				btn.classList.contains('current')
2624			) {
2625				return;
2626			}
2627			e.preventDefault();
2628			const currentPage = parseInt(
2629				pagination_section.dataset.current,
2630				10
2631			);
2632			let newPage = null;
2633
2634			if (btn.classList.contains('prev')) {
2635				newPage = currentPage - 1;
2636			} else if (btn.classList.contains('next')) {
2637				newPage = currentPage + 1;
2638			} else {
2639				newPage = parseInt(btn.dataset.page, 10);
2640			}
2641
2642			if (isNaN(newPage) || newPage === currentPage) {
2643				return;
2644			}
2645			// Get current filter state (if you have one).
2646
2647			const currentState = getFilterState(e);
2648			// Load the new page.
2649
2650			loadPage(newPage, 'replace', currentState);
2651			// Optional: update the data-current attribute.
2652
2653			pagination_section.dataset.current = newPage;
2654		});
2655		// Grid Nav Arrows (custom arrow buttons)
2656		const navArrows = pagination_section.querySelectorAll(
2657			'.sp-smart-post-grid-nav-arrow-btn'
2658		);
2659		if (navArrows.length === 2) {
2660			const [prevArrow, nextArrow] = navArrows;
2661			prevArrow.addEventListener('click', (e) => {
2662				e.preventDefault();
2663				currentState = getFilterState(e);
2664				loadPage(current - 1, 'replace', currentState);
2665			});
2666			nextArrow.addEventListener('click', (e) => {
2667				e.preventDefault();
2668				currentState = getFilterState(e);
2669				current = parseInt(pagination_section.dataset.current, 10);
2670				loadPage(current + 1, 'replace', currentState);
2671			});
2672		}
2673
2674		updatePaginationUI(pagination_section);
2675	});
2676
2677	/**
2678	 * Capitalizes the first letter of a string.
2679	 *
2680	 * @param {string} str - The string to capitalize.
2681	 * @return {string} - Capitalized string.
2682	 */
2683	function capitalize(str) {
2684		if (!str) {
2685			return '';
2686		}
2687		return str.charAt(0).toUpperCase() + str.slice(1);
2688	}
2689
2690	/**
2691	 * Updates the filter <select> options with post counts from the response.
2692	 *
2693	 * @param {Object}           termCounts         - Term count data (taxonomy → terms[]).
2694	 * @param {HTMLElement|null} pagination_section - Pagination DOM section (if exists).
2695	 * @param {HTMLElement}      blockParent        - The block wrapper containing filters.
2696	 */
2697	function updateFilterCounts(termCounts, pagination_section, blockParent) {
2698		if (!termCounts || !blockParent) {
2699			return;
2700		}
2701		const show_count = true;
2702		Object.entries(termCounts).forEach(([taxonomy, terms]) => {
2703			// Handle pagination update
2704			if (taxonomy === 'pagination' && pagination_section) {
2705				updatePaginationData(pagination_section, terms);
2706				return;
2707			}
2708
2709			// Find the filter select dropdown for the taxonomy
2710			const select = blockParent.querySelector(`#filter-${taxonomy}`);
2711			if (!select) {
2712				return;
2713			}
2714
2715			Array.from(select.options).forEach((option) => {
2716				const slug = option.value;
2717				if (!slug || !terms) {
2718					return;
2719				}
2720				const isSelected = option.selected;
2721				const defaultLabel = option.getAttribute('data-label') || slug;
2722				const term = terms.find((t) => t.slug == slug);
2723				if (term) {
2724					const count = show_count ? `(${term.count})` : '';
2725					// Term exists: show its updated count.
2726					option.textContent = `${capitalize(defaultLabel)} ${count}`;
2727					option.disabled = false;
2728				} else {
2729					// Term not in result: disable unless selected.
2730					const count = show_count ? `(0)` : '';
2731					option.textContent = `${capitalize(defaultLabel)} (0)`;
2732					option.disabled = !isSelected;
2733				}
2734			});
2735		});
2736	}
2737
2738	/**
2739	 * Resets all filter dropdowns to their default counts (used when no filters are active).
2740	 *
2741	 * @param {HTMLElement} blockParent - The block wrapper containing filters.
2742	 */
2743	function resetFilterCounts(blockParent) {
2744		if (!blockParent) {
2745			return;
2746		}
2747
2748		blockParent
2749			.querySelectorAll('.sp-smart-filter-area select option')
2750			.forEach((option) => {
2751				const slug = option.value;
2752				if (!slug) {
2753					return;
2754				} // Skip the "All" or blank option
2755
2756				const defaultCount = option.getAttribute('data-default-count');
2757				if (defaultCount !== null) {
2758					option.textContent = `${capitalize(
2759						option.getAttribute('data-label') || slug
2760					)} (${defaultCount})`;
2761					option.disabled = false;
2762				}
2763			});
2764	}
2765	//-------------------------------------
2766
2767	const filterWrappers = document.querySelectorAll(
2768		'.sp-smart-post-taxonomy-filter, .sp-smart-post-sort-filter'
2769	);
2770
2771	// Common handler function for dropdown items
2772	function handleDropdownClick(
2773		e,
2774		dropdown,
2775		oppositeDropdown,
2776		spanLabel,
2777		select
2778	) {
2779		const item = e.target.closest('a');
2780		if (!item || item.classList.contains('disabled')) return;
2781
2782		e.preventDefault();
2783
2784		// Remove active class from opposite dropdown if exists
2785		if (oppositeDropdown) {
2786			const links = oppositeDropdown.querySelectorAll(
2787				'.sps-live-filter-nav-link'
2788			);
2789			links.forEach((link) => link.classList.remove('active'));
2790		}
2791
2792		// Remove active from all items in current dropdown
2793		dropdown
2794			.querySelectorAll('a')
2795			.forEach((el) => el.classList.remove('active'));
2796
2797		// Add active to clicked item
2798		item.classList.add('active');
2799
2800		// Extract values
2801		const value = item.getAttribute('data-value');
2802		const label = item.getAttribute('data-label');
2803		const countMatch = item.textContent.match(/\((\d+)\)/);
2804		const count = countMatch ? countMatch[1] : '';
2805
2806		// Update button label
2807		if (spanLabel) {
2808			spanLabel.innerHTML = `${label}${count ? ` (${count})` : ''}`;
2809		}
2810
2811		// Update select and trigger change
2812		if (select) {
2813			select.value = value;
2814			select.dispatchEvent(new Event('change'));
2815		}
2816
2817		// Close dropdown
2818		dropdown.classList.remove('open');
2819	}
2820
2821	// Setup function for each filter wrapper
2822	function setupFilterWrapper(wrapper) {
2823		const btn = wrapper.querySelector('.sp-smart-post-live-filter-btn');
2824		const dropdown = wrapper.querySelector(
2825			'.sp-smart-post-live-filter-dropdown, .sp-smart-post-live-filter-button, .sp-smart-post-live-filter-button-date'
2826		);
2827		const secondDropdown = wrapper.querySelector(
2828			'.sps-live-filter-dropdown-menu'
2829		);
2830		const spanLabel = btn?.querySelector('span');
2831
2832		// Find the closest hidden select
2833		const select = wrapper
2834			.closest('.sp-smart-post-live-filter-wrapper')
2835			?.querySelector('select');
2836
2837		if (!select) {
2838			return;
2839		}
2840
2841		// Setup dropdown toggle
2842		if (btn && dropdown) {
2843			btn.addEventListener('click', (e) => {
2844				e.preventDefault();
2845				dropdown.classList.toggle('open');
2846			});
2847		}
2848
2849		// Setup dropdown click handlers
2850		if (dropdown) {
2851			dropdown.addEventListener('click', (e) =>
2852				handleDropdownClick(
2853					e,
2854					dropdown,
2855					secondDropdown,
2856					spanLabel,
2857					select
2858				)
2859			);
2860		}
2861
2862		if (secondDropdown) {
2863			secondDropdown.addEventListener('click', (e) =>
2864				handleDropdownClick(
2865					e,
2866					secondDropdown,
2867					dropdown,
2868					spanLabel,
2869					select
2870				)
2871			);
2872		}
2873	}
2874
2875	// Initialize all filter wrappers
2876	filterWrappers.forEach(setupFilterWrapper);
2877
2878	// Single event listener for closing dropdowns on outside click
2879	document.addEventListener('click', (e) => {
2880		document
2881			.querySelectorAll('.sp-smart-post-live-filter-dropdown.open')
2882			.forEach((dropdown) => {
2883				const btn = dropdown.previousElementSibling;
2884				if (
2885					!dropdown.contains(e.target) &&
2886					(!btn || !btn.contains(e.target))
2887				) {
2888					dropdown.classList.remove('open');
2889				}
2890			});
2891	});
2892	//---------------------------------------
2893	/**
2894	 * Utility: Wait until all images inside an element are loaded before running a callback.
2895	 *
2896	 * @param {HTMLElement} el       - The container element to monitor.
2897	 * @param {Function}    callback - Function to call once all images are loaded.
2898	 */
2899	const imagesLoaded = (el, callback) => {
2900		const images = el.querySelectorAll('img');
2901		let loadedCount = 0;
2902
2903		// No images? Run callback immediately
2904		if (images.length === 0) {
2905			return callback();
2906		}
2907
2908		images.forEach((img) => {
2909			if (img.complete) {
2910				loadedCount++;
2911				if (loadedCount === images.length) {
2912					callback();
2913				}
2914			} else {
2915				img.onload = img.onerror = () => {
2916					loadedCount++;
2917					if (loadedCount === images.length) {
2918						callback();
2919					}
2920				};
2921			}
2922		});
2923	};
2924
2925	/**
2926	 * Utility: Get the unique block ID from an element's closest wrapper.
2927	 *
2928	 * @param {HTMLElement} child - A child element inside the block.
2929	 * @return {string|null} - Block ID or null.
2930	 */
2931	const getBlockIdFromChild = (child) => {
2932		const wrapper = child.closest('.sp-smart-post-wrapper');
2933		return wrapper ? wrapper.id : null;
2934	};
2935
2936	/**
2937	 * Equal height logic for carousel items (Swiper cards).
2938	 */
2939	const carouselContainers = document.querySelectorAll(
2940		'.sp-smart-post-swiper.sp-equal-height-wrapper'
2941	);
2942
2943	carouselContainers.forEach((carousel) => {
2944		const containerId = getBlockIdFromChild(carousel);
2945		const equalHeightEnabled = carousel.dataset.equalHeight == '1';
2946		let container = document.getElementById(containerId);
2947
2948		// Check inside iframe (used in editors like block preview)
2949		if (!container) {
2950			const iframe = document.querySelector('iframe');
2951			const iframeDoc = iframe?.contentWindow?.document;
2952			container = iframeDoc?.getElementById(containerId) || null;
2953		}
2954
2955		if (container) {
2956			const cards = container.querySelectorAll('.sp-smart-post-card');
2957
2958			const applyEqualHeight = () => {
2959				if (!cards.length) {
2960					return;
2961				}
2962
2963				if (equalHeightEnabled) {
2964					// Calculate max height
2965					let maxHeight = 0;
2966					cards.forEach((card) => {
2967						card.style.height = 'auto'; // reset first
2968						const height = card.offsetHeight;
2969						if (height > maxHeight) {
2970							maxHeight = height;
2971						}
2972					});
2973					// Apply max height to all cards
2974					cards.forEach((card) => {
2975						card.style.height = `${maxHeight}px`;
2976					});
2977				} else {
2978					// Reset to auto
2979					cards.forEach((card) => {
2980						card.style.height = 'auto';
2981					});
2982				}
2983			};
2984			// Apply after all images load
2985			imagesLoaded(container, applyEqualHeight);
2986		}
2987	});
2988	// Update selection count field.
2989	update_selection_field_count();
2990
2991	const containers = document.querySelectorAll('.sps-live-filter-layout-two');
2992
2993	containers.forEach((container) => {
2994		const style = container.dataset.style;
2995		let currentPage = parseInt(container.dataset.currentPage);
2996		let isDropdownOpen = container.dataset.isDropdownOpen === 'true';
2997		const totalPages = parseInt(container.dataset.totalPages);
2998
2999		const dropdown = container.querySelector('.sps-live-filter-dropdown');
3000		const dropdownList = container.querySelector(
3001			'.sps-live-filter-dropdown-menu'
3002		);
3003		if (dropdownList && dropdownList?.children.length === 0) {
3004			dropdown.style.display = 'none';
3005		}
3006
3007		// State management functions
3008		function updateState() {
3009			// container.dataset.activeItem = activeItem;
3010			container.dataset.currentPage = currentPage;
3011			container.dataset.isDropdownOpen = isDropdownOpen;
3012		}
3013
3014		function toggleDropdown() {
3015			isDropdownOpen = !isDropdownOpen;
3016			updateState();
3017			updateUI();
3018		}
3019
3020		function closeDropdown() {
3021			isDropdownOpen = false;
3022			updateState();
3023			updateUI();
3024		}
3025
3026		function nextPage() {
3027			if (currentPage < totalPages - 1) {
3028				currentPage++;
3029				updateState();
3030			}
3031		}
3032
3033		function prevPage() {
3034			if (currentPage > 0) {
3035				currentPage--;
3036				updateState();
3037				// updatePage();
3038			}
3039		}
3040
3041		// UI update function
3042		function updateUI() {
3043			// Update dropdown visibility
3044			if (dropdown) {
3045				if (isDropdownOpen) {
3046					dropdown.classList.add('active');
3047				} else {
3048					dropdown.classList.remove('active');
3049				}
3050			}
3051		}
3052
3053		// Event handlers - using event delegation
3054		container.addEventListener('click', function (e) {
3055			// Handle term clicks (including dynamically created ones)
3056			if (
3057				e.target.closest('.sps-live-filter-nav-link') &&
3058				!e.target.closest('.sps-live-filter-dropdown')
3059			) {
3060				e.preventDefault();
3061				const id = e.target.closest('.sps-live-filter-nav-link').dataset
3062					.id;
3063				// setActiveItem(id);
3064			}
3065
3066			// Handle dropdown toggle
3067			if (
3068				e.target.closest(
3069					'.sps-live-filter-dropdown .sps-live-filter-nav-link'
3070				)
3071			) {
3072				e.preventDefault();
3073				if (style !== 'navigation') {
3074					toggleDropdown();
3075				}
3076			}
3077
3078			// Handle dropdown item clicks
3079			if (e.target.closest('.sps-live-filter-dropdown-item')) {
3080				e.preventDefault();
3081				const id = e.target.closest('.sps-live-filter-dropdown-item')
3082					.dataset.id;
3083				// setActiveItem(id);
3084			}
3085
3086			// Handle pagination clicks.
3087			if (e.target.closest('.sps-pagination-prev')) {
3088				e.preventDefault();
3089				prevPage();
3090			}
3091
3092			if (e.target.closest('.sps-pagination-next')) {
3093				e.preventDefault();
3094				nextPage();
3095			}
3096		});
3097
3098		// Close dropdown when clicking outside.
3099		document.addEventListener('click', function (e) {
3100			if (!container.contains(e.target)) {
3101				closeDropdown();
3102			}
3103		});
3104	});
3105
3106	// Initialize smart post features on dynamically loaded content
3107	wrapLines();
3108}
3109
3110// Expose init function to window object so it can be called from other files
3111window.init = init;
3112
3113/**
3114 * Initializes or updates all smart filter dropdowns on the page.
3115 */
3116function update_selection_field_count() {
3117	document
3118		.querySelectorAll('.sp-smart-post-live-filter-wrapper')
3119		.forEach((wrapper) => {
3120			const selectEl = wrapper.querySelector('select');
3121			const dropdownUl = wrapper.querySelector(
3122				'.sp-smart-post-live-filter-dropdown, .sp-smart-post-live-filter-button, .sp-smart-post-live-filter-button-date'
3123			);
3124			const moreButton = wrapper.querySelector(
3125				'.sps-live-filter-dropdown-menu'
3126			);
3127			buildSmartFilterDropdown(selectEl, dropdownUl, moreButton);
3128		});
3129}
3130
3131function buildSmartFilterDropdown(selectEl, dropdownUl, moreButton) {
3132	if (!selectEl || !dropdownUl) return;
3133
3134	// Clear existing dropdown items
3135	dropdownUl.innerHTML = '';
3136	if (moreButton) moreButton.innerHTML = '';
3137
3138	const options = Array.from(selectEl.options);
3139
3140	let attributes = {};
3141	try {
3142		const dataAtt = selectEl.dataset.att;
3143		attributes =
3144			dataAtt && dataAtt !== 'undefined' ? JSON.parse(dataAtt) : {};
3145	} catch (e) {
3146		console.warn('Invalid JSON in data-att:', e);
3147		attributes = {};
3148	}
3149	const { taxonomyLimit, taxonomyStyle, filterType, uniqueId } = attributes;
3150
3151	let device = 'Desktop';
3152
3153	if (window.innerWidth <= 781) device = 'Mobile';
3154	else if (window.innerWidth <= 1024) device = 'Tablet';
3155
3156	// Safely access taxonomyLimit.device
3157	const limit =
3158		taxonomyLimit && taxonomyLimit.device
3159			? taxonomyLimit.device[device] || 3
3160			: 3;
3161
3162	if (taxonomyStyle === 'navigation') {
3163		// Initialize pagination state
3164		let currentPage = parseInt(dropdownUl.dataset.currentPage) || 1;
3165		const totalPages = Math.ceil(options.length / limit);
3166
3167		// Ensure current page is within valid range
3168		currentPage = Math.max(1, Math.min(currentPage, totalPages));
3169		dropdownUl.dataset.currentPage = currentPage;
3170
3171		// Calculate current page items
3172		const startIndex = (currentPage - 1) * limit;
3173		const endIndex = startIndex + limit;
3174		const currentOptions = options.slice(startIndex, endIndex);
3175
3176		// Add current page options to dropdown
3177		currentOptions.forEach((option) => {
3178			const value = option.value;
3179			if (value === undefined) return;
3180
3181			const label =
3182				option.getAttribute('data-label') || option.textContent.trim();
3183			const count = option.getAttribute('data-default-count') || '';
3184			const isSelected = option.selected ?? false;
3185			const isDisabled = parseInt(count) === 0;
3186
3187			const li = document.createElement('li');
3188			const a = document.createElement('a');
3189			li.classList.add('sps-live-filter-nav-item');
3190			a.classList.add('sps-live-filter-nav-link');
3191
3192			a.href = '#';
3193			a.setAttribute('data-value', value);
3194			a.setAttribute('data-label', label);
3195			a.textContent = `${label}${count ? ` (${count})` : ''}`;
3196
3197			//   if (!count && selectEl.id !== "filter-sort") {
3198			//     a.classList.add("active");
3199			//   }
3200
3201			li.appendChild(a);
3202			if (label) {
3203				dropdownUl.appendChild(li);
3204			}
3205		});
3206
3207		// Create pagination controls
3208		const paginationContainer = document.createElement('div');
3209		paginationContainer.className = 'pagination-controls';
3210
3211		// const container = document.querySelector(".sps-live-filter-layout-two");
3212		const container = document.querySelector(`#${uniqueId}`);
3213		const prev = container.querySelector('.sps-pagination-prev');
3214		const next = container.querySelector('.sps-pagination-next');
3215
3216		prev.addEventListener('click', () => {
3217			dropdownUl.dataset.currentPage = currentPage - 1;
3218			buildSmartFilterDropdown(selectEl, dropdownUl, moreButton);
3219		});
3220
3221		// Page indicator
3222		const pageIndicator = document.createElement('span');
3223		pageIndicator.className = 'pagination-info';
3224		pageIndicator.textContent = `Page ${currentPage} of ${totalPages}`;
3225
3226		next.addEventListener('click', () => {
3227			dropdownUl.dataset.currentPage = currentPage + 1;
3228			buildSmartFilterDropdown(selectEl, dropdownUl, moreButton);
3229		});
3230	} else if (moreButton) {
3231		// Non-navigation style with more button
3232		const optionsOne = options.slice(0, limit);
3233		const optionsTwo = options.slice(limit);
3234
3235		// Add first set of options to dropdown
3236
3237		if (filterType !== 'dropdown') {
3238			optionsOne.forEach((option) => {
3239				const value = option.value;
3240				if (value === undefined) return;
3241
3242				const label =
3243					option.getAttribute('data-label') ||
3244					option.textContent.trim();
3245				const count = option.getAttribute('data-default-count') || '';
3246				const li = document.createElement('li');
3247				const a = document.createElement('a');
3248				li.classList.add('sps-live-filter-nav-item');
3249				a.classList.add('sps-live-filter-nav-link');
3250				if (label === 'All') {
3251					a.classList.add('active');
3252				}
3253
3254				a.href = '#';
3255				a.setAttribute('data-value', value);
3256				a.setAttribute('data-label', label);
3257				a.textContent = `${label}${count ? ` (${count})` : ''}`;
3258
3259				li.appendChild(a);
3260				if (label) {
3261					dropdownUl.appendChild(li);
3262				}
3263			});
3264		}
3265
3266		// Add remaining options to more button
3267		Array.from(filterType === 'dropdown' ? options : optionsTwo).forEach(
3268			(option) => {
3269				const value = option.value;
3270				if (value === undefined) return;
3271				const label =
3272					option.getAttribute('data-label') ||
3273					option.textContent.trim();
3274
3275				const a = document.createElement('a');
3276				a.classList.add('sps-live-filter-nav-link');
3277				a.href = '#';
3278				a.setAttribute('data-value', value);
3279				a.setAttribute('data-label', label);
3280				a.textContent = label;
3281
3282				moreButton.appendChild(a);
3283			}
3284		);
3285	} else {
3286		// No more button - add all options to dropdown
3287		options.forEach((option) => {
3288			const value = option.value;
3289			if (value === undefined) return;
3290
3291			const label =
3292				option.getAttribute('data-label') || option.textContent.trim();
3293			const count = option.getAttribute('data-default-count') || '';
3294
3295			const li = document.createElement('li');
3296			const a = document.createElement('a');
3297			li.classList.add('sps-live-filter-nav-item');
3298			a.classList.add('sps-live-filter-nav-link');
3299
3300			a.href = '#';
3301			a.setAttribute('data-value', value);
3302			a.setAttribute('data-label', label);
3303			a.textContent = `${label}${count ? ` (${count})` : ''}`;
3304
3305			if (!count && selectEl.id !== 'filter-sort') {
3306				a.classList.add('active');
3307			}
3308
3309			li.appendChild(a);
3310			dropdownUl.appendChild(li);
3311		});
3312	}
3313}
3314
3315//................................ second layout part 2...................................................................
3316
3317/**
3318 * Updates all custom dropdowns and their labels based on selected values.
3319 *
3320 * @param {HTMLElement} blockParent - The parent block element containing filter wrappers.
3321 */
3322function updateAllSmartPostFilterCounts(blockParent) {
3323	const wrappers = blockParent.querySelectorAll(
3324		'.sp-smart-post-live-filter-wrapper'
3325	);
3326
3327	wrappers.forEach((wrapper) => {
3328		const select = wrapper.querySelector('select');
3329		const dropdown = wrapper.querySelector(
3330			'.sp-smart-post-live-filter-dropdown, .sp-smart-post-live-filter-button, .sp-smart-post-live-filter-button-date'
3331		);
3332		const selectedButton = wrapper.querySelector(
3333			'.sp-smart-post-live-filter-btn span'
3334		);
3335		const this_filter = wrapper.querySelector('.sp-smart-post-live-filter');
3336		if (select.id === 'filter-sort') {
3337			// Build map: value → { label, count }
3338			const optionMap = Array.from(select.options).reduce(
3339				(map, option) => {
3340					const value = option.value;
3341					const label =
3342						option.getAttribute('data-label') ||
3343						option.textContent.trim();
3344					// Extract count from text, fallback to 0
3345					const isSelected = option.selected ?? false;
3346					map[value] = { label, isSelected };
3347					return map;
3348				},
3349				{}
3350			);
3351			dropdown.querySelectorAll('a').forEach((a) => {
3352				const value = a.getAttribute('data-value');
3353				const { label, isSelected } = optionMap[value];
3354				if (isSelected) {
3355					dropdown
3356						.querySelectorAll('a')
3357						.forEach((el) => el.classList.remove('active'));
3358					a.classList.add('active');
3359				}
3360			});
3361			// Update selected button label
3362			if (select.value && selectedButton) {
3363				const { label, count } = optionMap[select.value] || {};
3364				if (label !== undefined) {
3365					selectedButton.textContent = `${label}`;
3366				}
3367			}
3368		}
3369
3370		if (!select || !dropdown || select.id === 'filter-sort') {
3371			return;
3372		}
3373		const show_count = this_filter?.getAttribute('data-show-count');
3374		// Build map: value → { label, count }
3375		const optionMap = Array.from(select.options).reduce((map, option) => {
3376			const value = option.value;
3377			const label =
3378				option.getAttribute('data-label') || option.textContent.trim();
3379			// Extract count from text, fallback to 0
3380			const countMatch = option.textContent.trim().match(/\((\d+)\)/);
3381			const count = countMatch ? countMatch[1] : '0';
3382			const isSelected = option.selected ?? false;
3383			map[value] = { label, count, isSelected };
3384			return map;
3385		}, {});
3386
3387		// Update selected button label
3388		if (select.value && selectedButton) {
3389			const { label, count } = optionMap[select.value] || {};
3390			const count_text = show_count ? `(${count})` : '';
3391			if (label !== undefined) {
3392				selectedButton.textContent = `${label} ${count_text}`;
3393			}
3394		}
3395
3396		// Update dropdown items with latest labels and counts
3397		dropdown.querySelectorAll('a').forEach((a) => {
3398			const value = a.getAttribute('data-value');
3399			if (!value || !optionMap[value]) {
3400				return;
3401			}
3402
3403			const { label, count, isSelected } = optionMap[value];
3404
3405			a.setAttribute('data-label', label);
3406			a.setAttribute('data-default-count', count);
3407			const count_text = show_count ? `(${count})` : '';
3408			a.textContent = `${label} ${count_text}`;
3409			if (parseInt(count) === 0) {
3410				a.classList.add('disabled');
3411				a.setAttribute('aria-disabled', 'true');
3412			} else {
3413				a.classList.remove('disabled');
3414				a.removeAttribute('aria-disabled');
3415				if (isSelected) {
3416					dropdown
3417						.querySelectorAll('a')
3418						.forEach((el) => el.classList.remove('active'));
3419					a.classList.add('active');
3420				}
3421			}
3422		});
3423	});
3424}
3425
3426//------------------------title effect js--------
3427function wrapLines() {
3428	const selector = `
3429        .sp-smart-post-grid-two .sp-smart-post-title,
3430        .sp-smart-post-grid-three .sp-smart-post-title,
3431        .sp-smart-post-carousel-two .sp-smart-post-title,
3432        .sp-smart-post-slider .sp-smart-post-title,
3433        .sp-smart-post-slider-two .sp-smart-post-title,
3434        .sp-smart-post-thumbnail-slider .sp-smart-post-title,
3435        .sp-smart-post-thumbnail-slide-two .sp-smart-post-title,
3436        .sp-smart-post-grid-four .sp-smart-post-title,
3437        .sp-smart-post-grid-five .sp-smart-post-title,
3438        .sp-smart-post-grid-six .sp-smart-post-title,
3439        .sp-smart-post-timeline-two .sp-smart-post-title`;
3440
3441	document.querySelectorAll(selector).forEach((title) => {
3442		if (title.dataset.processed === 'true') return;
3443
3444		const textElement = title.querySelector('.sp-smart-post-title-text');
3445		if (!textElement) return;
3446
3447		// Get trimmed text content only from title-text span
3448		const text = textElement.textContent.trim();
3449		if (!text) return;
3450
3451		const temp = document.createElement('div');
3452		const style = window.getComputedStyle(textElement);
3453		Object.assign(temp.style, {
3454			position: 'absolute',
3455			visibility: 'hidden',
3456			whiteSpace: 'nowrap',
3457			fontSize: style.fontSize,
3458			fontFamily: style.fontFamily,
3459			fontWeight: style.fontWeight,
3460		});
3461		document.body.appendChild(temp);
3462
3463		const containerWidth = textElement.offsetWidth || title.offsetWidth;
3464		const words = text.split(' ');
3465		const lines = [];
3466		let currentLine = '';
3467
3468		words.forEach((word) => {
3469			const testLine = currentLine ? `${currentLine} ${word}` : word;
3470			temp.textContent = testLine;
3471			if (temp.offsetWidth > containerWidth && currentLine) {
3472				lines.push(currentLine);
3473				currentLine = word;
3474			} else {
3475				currentLine = testLine;
3476			}
3477		});
3478		if (currentLine) lines.push(currentLine);
3479		document.body.removeChild(temp);
3480
3481		textElement.innerHTML = ''; // clear only text span
3482
3483		lines.forEach((line, index) => {
3484			const span = document.createElement('span');
3485			span.className = 'line';
3486			span.textContent = line;
3487			textElement.appendChild(span);
3488			if (index < lines.length - 1) {
3489				textElement.appendChild(document.createElement('br'));
3490			}
3491		});
3492
3493		title.dataset.processed = 'true';
3494	});
3495}

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.