PageSourceSearch

https://stmundial.com/wp-content/plugins/socialfeeds/assets/js/frontend.js?ver=1.0.7

js stmundial.com collected 2026-09-24 14:53:38 UTC 14,043 bytes, 384 lines download raw bytes

1jQuery(document).ready(function ($) {
2
3	// ===== Video play mode: LIGHTBOX, INLINE, NEWTAB =====
4	$('.socialfeeds-youtube-feed').on('click','.socialfeeds-video-item a, .socialfeeds-media-link, .socialfeeds-carousel-item a, .socialfeeds-list-item iframe',function(e){
5  	let $link = $(this).closest('a');
6		if (!$link.length) $link = $(this);
7
8		// If it's an iframe click (list view), let it be
9		if ($link.is('iframe')) return;
10
11		let $feed = $link.closest('.socialfeeds-youtube-feed');
12		if (!$feed.length) return;
13
14		let click_action = $feed.data('click') || $feed.attr('data-click') || 'newtab';
15
16		// 1. New Tab (Default behavior)
17		if (click_action === 'newtab') {
18			return; // Let default click happen
19		}
20
21		e.preventDefault();
22		let href = $link.attr('href');
23		if (!href) return;
24
25		let vid_match = href.match(/[?&]v=([^&]+)/) || href.match(/youtu\.be\/([^?&]+)/) || href.split('/').pop().match(/^([a-zA-Z0-9_-]{11})/);
26		let vid = vid_match ? vid_match[1] : '';
27
28		if (!vid) {
29			// Fallback if video ID not found
30			window.open(href, '_blank');
31			return;
32		}
33
34		// 2. Lightbox
35		if (click_action === 'lightbox'){
36			let modal_html = `
37				<div class="socialfeeds-modal">
38					<div class="socialfeeds-modal-backdrop"></div>
39					<div class="socialfeeds-modal-inner" style="width: 900px; max-width: 90vw; background: #000;">
40						<button class="socialfeeds-modal-close" style="z-index:100; color:#fff; background:rgba(0,0,0,0.5);">×</button>
41						<div class="socialfeeds-modal-content" style="position:relative; width:100%; aspect-ratio:16/9;">
42							<iframe src="https://www.youtube.com/embed/${encodeURIComponent(vid)}?autoplay=1&rel=0" 
43								frameborder="0" 
44								allow="autoplay; encrypted-media" 
45								allowfullscreen
46								style="position:absolute; top:0; left:0; width:100%; height:100%;">
47							</iframe>
48						</div>
49					</div>
50				</div>`;
51
52			$('body').append(modal_html);
53			setTimeout(() => $('.socialfeeds-modal').addClass('active'), 10);
54			return;
55		}
56
57		// 3. Inline
58		if(click_action === 'inline'){
59			// Find the play overlay and hide it (if it exists)
60			let $overlay = $link.siblings('.socialfeeds-play-overlay');
61			if ($overlay.length) $overlay.hide();
62
63			// Should specifically target the media container to keep title/desc intact
64			$link.replaceWith(`
65				<iframe src="https://www.youtube.com/embed/${encodeURIComponent(vid)}?autoplay=1&mute=0&rel=0&playsinline=1"
66					frameborder="0"
67					allow="autoplay; encrypted-media"
68					allowfullscreen
69					style="width:100%; aspect-ratio:16/9; display:block;">
70				</iframe>
71			`);
72		}
73	});
74
75	$(document).on('click', '.socialfeeds-modal-close, .socialfeeds-modal-backdrop', function (e) {
76		$('.socialfeeds-modal').removeClass('active');
77		setTimeout(() => $('.socialfeeds-modal').remove(), 300);
78	});
79
80	// ===== LOAD MORE (AJAX) =====
81	$('.socialfeeds-load-more-btn').on('click', function (e){
82		e.preventDefault();
83		let $btn = $(this);
84		if ($btn.data('feed-type') === 'instagram') {
85			return;
86		}
87		let feed_id = $btn.data('feed-id'),
88			feed_type = $btn.data('feed-type'),
89			feed_input = $btn.data('feed-input'),
90			limit = parseInt($btn.data('limit'), 10),
91			loaded = parseInt($btn.data('loaded'), 10),
92			page_token = $btn.attr('data-page-token') || '',
93			$feed = $btn.closest('.socialfeeds-youtube-feed');
94
95
96		if (!feed_type || !feed_input) {
97			console.error('SocialFeeds: Missing required parameters for Load More');
98			return;
99		}
100
101		$btn.prop('disabled', true).addClass('socialfeeds-loading');
102		let original_text = $btn.text();
103
104		let ajax_data = {
105			action: 'socialfeeds_load_more_videos',
106			feed_id: feed_id,
107			feed_type: feed_type,
108			feed_input: feed_input,
109			limit: limit,
110			pageToken: page_token,
111			nonce: socialfeeds_ajax.nonce
112		};
113
114		$.ajax({
115			url: socialfeeds_ajax.ajax_url,
116			type: 'POST',
117			data: ajax_data,
118			dataType: 'json',
119			success: function (response) {
120				if (!response.success) {
121					$btn.prop('disabled', false).removeClass('socialfeeds-loading').text('Error loading videos');
122					return;
123				}
124
125				let data = response.data;
126
127				if (data && data.html) {
128
129					let $feed = $btn.closest('.socialfeeds-youtube-feed');
130					let $itemsContainer = $feed.find('.socialfeeds-youtube-grid, .socialfeeds-youtube-list, .socialfeeds-youtube-carou
130sel');
131
132					// Fallback if not found
133					if (!$itemsContainer.length) {
134						$itemsContainer = $btn.closest('.socialfeeds-load-more-container');
135					}
136
137					if ($itemsContainer.length && !$itemsContainer.hasClass('socialfeeds-load-more-container')) {
138						$itemsContainer.append(data.html);
139					} else {
140						$btn.closest('.socialfeeds-load-more-container').before(data.html);
141					}
142
143					let loaded_count = (data.items && data.items.length) ? data.items.length : 1;
144
145					let new_loaded = loaded + loaded_count;
146					$btn.data('loaded', new_loaded).attr('data-loaded', new_loaded);
147
148					if (data.nextPageToken) {
149						$btn.attr('data-page-token', data.nextPageToken);
150						$btn.prop('disabled', false).removeClass('socialfeeds-loading').text(original_text);
151					} else {
152						$btn.text($btn.data('no-more-text') || 'No More Videos').hide();
153					}
154
155					if ($itemsContainer.hasClass('socialfeeds-youtube-carousel')) {
156						$(window).trigger('resize');
157					}
158
159				} else if (data && data.items && data.items.length > 0) {
160					let items = data.items;
161
162					// Find the inner container where items live
163					let $itemsContainer = $feed.find('.socialfeeds-youtube-grid, .socialfeeds-youtube-list, .socialfeeds-youtube-carousel');
164
165					// Fallback if not found (shouldn't happen if structure is valid)
166					if(!$itemsContainer.length){
167						$itemsContainer = $btn.closest('.socialfeeds-load-more-container');
168					}
169
170					let is_grid = $itemsContainer.hasClass('socialfeeds-youtube-grid');
171					let is_carousel = $itemsContainer.hasClass('socialfeeds-youtube-carousel');
172					let is_list = $itemsContainer.hasClass('socialfeeds-youtube-list');
173
174					items.forEach(function (item) {
175						let vid = item.videoId;
176						let title = item.title || 'Video';
177						let thumb = (item.thumbnails && item.thumbnails.medium) ? item.thumbnails.medium.url :
178							((item.thumbnails && item.thumbnails.default) ? item.thumbnails.default.url : '');
179						let desc = item.description || '';
180						let short_desc = desc ? (desc.substring(0, 54) + '...') : '';
181
182						let item_html = '';
183						if (is_grid) {
184							item_html = `
185									<div class="socialfeeds-video-item">
186										<a href="https://www.youtube.com/watch?v=${vid}" target="_blank" rel="noopener">
187											<img src="${thumb}" alt="${title}" />
188										</a>
189										${title ? `<h5 class="socialfeeds-video-title">${title}</h5>` : ''}
190										${short_desc ? `<p class="socialfeeds-card-desc">${short_desc}</p>` : ''}
191									</div>`;
192						} else if (is_carousel) {
193							item_html = `
194									<div class="socialfeeds-video-item socialfeeds-carousel-item">
195										<a href="https://www.youtube.com/watch?v=${vid}" target="_blank" rel="noopener" style="display:block; position:relative;">
196											<img src="${thumb}" alt="${title}" />
197											<span class="socialfeeds-play-overlay"></span>
198										</a>
199										${title ? `<p class="socialfeeds-video-title">${title}</p>` : ''}
200									</div>`;
201						} else if (is_list) {
202							item_html = `
203									<div class="socialfeeds-video-item socialfeeds-list-item">
204										${title ? `<h3 class="socialfeeds-video-title">${title}</h3>` : ''}
205										<div class='socialfeeds-video-iframe-wrap'>
206											<iframe width="560" height="315" src="https://www.youtube.com/embed/${vid}" frameborder="0" allowfullscreen></iframe>
207										</div>
208										${short_desc ? `<p class="socialfeeds-video-desc">${short_desc}</p>` : ''}
209									</div>`;
210						} else {
211							// Default/Fallback
212							item_html = `
213									<div class="socialfeeds-video-item">
214										<a href="https://www.youtube.com/watch?v=${vid}" target="_blank" rel="noopener">
215											<img src="${thumb}" alt="${title}" />
216										</a>
217										${title ? `<h5 class="socialfeeds-video-title">${title}</h5>` : ''}
218										${short_desc ? `<p class="socialfeeds-card-desc">${short_desc}</p>` : ''}
219									</div>`;
220						}
221
222						// Append to the specific items container
223						if ($itemsContainer.length && !$itemsContainer.hasClass('socialfeeds-load-more-container')) {
224							$itemsContainer.append(item_html);
225						} else {
226							// Fallback: insert before button if we couldn't find the container
227							$btn.closest('.socialfeeds-load-more-container').before(item_html);
228						}
229					});
230
231					let new_loaded = loaded + items.length;
232					$btn.data('loaded', new_loaded).attr('data-loaded', new_loaded);
233
234					if (data.nextPageToken) {
235						$btn.attr('data-page-token', data.nextPageToken);
236						$btn.prop('disabled', false).removeClass('socialfeeds-loading').text(original_text);
237					} else {
238						$btn.text($btn.data('no-more-text') || 'No More Videos').hide();
239					}
240
241					// If we are in a carousel, trigger resize to update dots/nav
242					if(is_carousel){
243						$(window).trigger('resize');
244					}
245
246					// If items loaded are less than limit, we likely reached the end
247					if (items.length < limit) {
248						$btn.text($btn.data('no-more-text') || 'No More Videos').hide();
249					}
250
251				} else {
252					$btn.text($btn.data('no-more-text') || 'No More Videos').hide();
253				}
254			},
255			error: function (xhr, status, error) {
256				console.error('SocialFeeds AJAX Error:', error);
257				$btn.prop('disabled', false).removeClass('socialfeeds-loading').text('Error loading videos');
258			}
259		});
260	});
261
262	// ===== CAROUSEL INITIALIZATION =====
263	$('.socialfeeds-youtube-carousel').each(function () {
264		let $carousel = $(this);
265		let $feedWrapper = $carousel.closest('.socialfeeds-youtube-feed');
266
267		// Prevent double init
268		if ($feedWrapper.find('.socialfeeds-carousel-stage').length) return;
269
270		// 1. Wrap carousel in a stage for absolute positioning of arrows
271		// We want the stage to include the carousel but NOT the load more button if it's there
272		$carousel.wrap('<div class="socialfeeds-carousel-stage" style="position:relative;"></div>');
273		let $stage = $carousel.parent();
274
275		// 2. Create Nav Buttons (Inside Stage)
276		let $nav = $('<div class="socialfeeds-carousel-nav">' +
277			'<button class="socialfeeds-carousel-btn prev" aria-label="Previous" type="button"><span class="dashicons dashicons-arrow-left-alt2" style="font-family:dashicons; line-height:inherit;"></span></button>' +
278			'<button class="socialfeeds-carousel-btn next" aria-label="Next" type="button"><span class="dashicons dashicons-arrow-right-alt2" style="font-family:dashicons; line-height:inherit;"></span></button>' +
279			'</div>');
280
281		$stage.append($nav);
282
283		// 3. Create Dots (After Stage)
284		let $dots = $('<div class="socialfeeds-carousel-dots"></div>');
285		$stage.after($dots);
286
287		// If there is a load more container, ensure it is after dots
288		let $loadMore = $feedWrapper.find('.socialfeeds-load-more-container');
289		if ($loadMore.length) {
290			$feedWrapper.append($loadMore); // Move it to the very end
291		}
292
293		function updateDots() {
294			$dots.empty();
295			let scrollW = $carousel[0].scrollWidth;
296			let clientW = $carousel[0].clientWidth;
297			if (clientW >= scrollW) {
298				$dots.hide();
299				$nav.hide();
300				return;
301			}
302
303			$dots.show();
304			$nav.show();
305
306			// Simple pagination: items per page
307			let itemW = $carousel.find('.socialfeeds-carousel-item').first().outerWidth(true) || 300;
308			let itemsPerPage = Math.floor(clientW / itemW) || 1;
309			let totalItems = $carousel.find('.socialfeeds-carousel-item').length;
310			let pageCount = Math.ceil(totalItems / itemsPerPage);
311
312			// If scrolling is continuous, we approximate pages based on scrollWidth
313			pageCount = Math.ceil(scrollW / clientW);
314
315			for (let i = 0; i < pageCount; i++) {
316				let $d = $('<span class="socialfeeds-dot"></span>');
317				if (i === 0) $d.addClass('active');
318				$d.data('page', i);
319				$dots.append($d);
320			}
321		}
322
323		// Initial calc
324		setTimeout(updateDots, 500); // delay for layout settle
325		$(window).on('resize', updateDots);
326
327		// 4. Scroll Logic
328		$nav.find('.prev').on('click', function (e) {
329			e.preventDefault();
330			let itemW = $carousel.find('.socialfeeds-carousel-item').first().outerWidth(true) || 300;
331			$carousel.animate({ scrollLeft: $carousel.scrollLeft() - itemW }, 300, update_active_dot);
332		});
333
334		$nav.find('.next').on('click', function (e) {
335			e.preventDefault();
336			let itemW = $carousel.find('.socialfeeds-carousel-item').first().outerWidth(true) || 300;
337			$carousel.animate({ scrollLeft: $carousel.scrollLeft() + itemW }, 300, update_active_dot);
338		});
339
340		// Dots Click
341		$dots.on('click', '.socialfeeds-dot', function () {
342			let page = $(this).data('page');
343			let clientW = $carousel[0].clientWidth;
344			$carousel.animate({ scrollLeft: page * clientW }, 400, update_active_dot);
345		});
346
347		function update_active_dot() {
348			let scroll_left = $carousel.scrollLeft();
349			let clientW = $carousel[0].clientWidth;
350			let page = Math.round(scroll_left / clientW);
351			$dots.find('.socialfeeds-dot').removeClass('active').eq(page).addClass('active');
352		}
353
354		$carousel.on('scroll', function () {
355			clearTimeout($carousel.data('scrollTimer'));
356			$carousel.data('scrollTimer', setTimeout(update_active_dot, 100));
357		});
358
359		// 5. Autoplay
360		if ($carousel.data('autoplay')) {
361			let speed = parseInt($carousel.data('autoplay-speed')) || 3000;
362			let interval;
363
364			function start_autoplay() {
365				interval = setInterval(function () {
366					if ($carousel.scrollLeft() + $carousel.innerWidth() >= $carousel[0].scrollWidth - 10) {
367						$carousel.animate({ scrollLeft: 0 }, 600, update_active_dot);
368					} else {
369						let itemW = $carousel.find('.socialfeeds-carousel-item').first().outerWidth(true) || 300;
370						$carousel.animate({ scrollLeft: $carousel.scrollLeft() + itemW }, 600, update_active_dot);
371					}
372				}, speed);
373			}
374
375			start_autoplay();
376
377			$stage.hover(
378				function () { clearInterval(interval); },
379				function () { start_autoplay(); }
380			);
381		}
382	});
383
384});

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.