PageSourceSearch

https://americanstudies.online/wp-content/plugins/socialfeeds-pro/assets/js/frontend.js?ver=1.0.7

js americanstudies.online collected 2026-10-06 05:59:05 UTC 10,545 bytes, 302 lines download raw bytes

1jQuery(document).ready(function ($) {
2
3	// ===== INSTAGRAM PREMIUM LIGHTBOX (Matches Preview) =====
4	function init_insta_Modal() {
5		if (window._socialfeeds_modal_inited) return;
6		window._socialfeeds_modal_inited = true;
7
8		$(document).on('click', '.socialfeeds-open-modal-media', function (e) {
9			let $feedContainer = $(this).closest('.socialfeeds-instagram-feed, .socialfeeds-facebook-feed');
10			let isFacebook = $feedContainer.hasClass('socialfeeds-facebook-feed');
11			let playMode = $feedContainer.attr('data-play-mode') || 'newtab';
12
13			// Only intercept if play mode is lightbox
14			if (playMode !== 'lightbox') return;
15
16			e.preventDefault();
17
18			let mediaUrl = $(this).attr('data-media') || $(this).find('img').attr('src') || '';
19			let type = $(this).attr('data-type') || 'IMAGE';
20			let permalink = $(this).attr('data-permalink') || '#';
21
22			if (!mediaUrl) return;
23
24			let media_content = '';
25			if (type === 'VIDEO') {
26				media_content = `
27					<video src="${mediaUrl}" controls autoplay 
28						style="max-width: 90vw; max-height: 80vh; border-radius: 12px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); border: 2px solid rgba(255,255,255,0.1);">
29						Your browser does not support the video tag.
30					</video>`;
31			} else {
32				media_content = `
33					<img src="${mediaUrl}" 
34						style="max-width: 90vw; max-height: 80vh; border-radius: 12px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); object-fit: contain; border: 2px solid rgba(255,255,255,0.1);">`;
35			}
36
37			const $lightbox = $(`
38				<div class="socialfeeds-premium-lightbox" style="position: fixed; inset: 0; z-index: 999999; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(8px); background: rgba(0, 0, 0, 0.85); opacity: 0; transition: opacity 0.3s ease;">
39					<button class="close-btn" style="position: absolute; top: 30px; right: 30px; width: 44px; height: 44px; background: rgba(255,255,255,0.1); border: none; border-radius: 50%; color: white; font-size: 24px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s;">&times;</button>
40					<div class="lightbox-content-wrap" style="transform: scale(0.9); transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);">
41						${media_content}
42						${permalink && permalink !== '#' ? `<div style="text-align: center; margin-top: 15px;"><a href="${permalink}" target="_blank" style="color: white; text-decoration: none; background: rgba(255,255,255,0.1); padding: 8px 16px; border-radius: 20px; font-size: 13px; font-weight: 500;">View on ${isFacebook ? 'Facebook' : 'Instagram'}</a></div>` : ''}
43					</div>
44				</div>
45			`);
46
47			$('body').append($lightbox);
48
49			// Animate In
50			setTimeout(() => {
51				$lightbox.css('opacity', '1');
52				$lightbox.find('.lightbox-content-wrap').css('transform', 'scale(1)');
53			}, 10);
54
55			const close_lightbox = () => {
56				$lightbox.css('opacity', '0');
57				$lightbox.find('.lightbox-content-wrap').css('transform', 'scale(0.9)');
58				setTimeout(() => $lightbox.remove(), 300);
59			};
60
61			$lightbox.on('click', function (evt) {
62				if (evt.target === this || $(evt.target).hasClass('close-btn')) {
63					close_lightbox();
64				}
65			});
66
67			$(document).on('keydown.sf_lightbox_frontend', function (evt) {
68				if (evt.key === 'Escape') {
69					close_lightbox();
70					$(document).off('keydown.sf_lightbox_frontend');
71				}
72			});
73		});
74	}
75
76	$('.socialfeeds-load-more-btn').on('click', function (e) {
77		e.preventDefault();
78
79		let $btn = $(this);
80		
81		let feedType = $btn.data('feed-type');
82
83		// ===== INSTAGRAM LOAD MORE =====
84		if (feedType === 'instagram') {
85			let nextUrl = $btn.attr('data-next-url');
86			let loaded = parseInt($btn.data('loaded'), 10) || 0;
87			let $feed = $btn.closest('.socialfeeds-instagram-feed');
88			let $itemsContainer = $feed.find('.socialfeeds-instagram-inner');
89
90			if (!nextUrl) {
91				$btn.hide();
92				return;
93			}
94
95			let original_text = $btn.text();
96			$btn.prop('disabled', true).addClass('socialfeeds-loading');
97
98			$.ajax({
99				url: socialfeeds_ajax.ajax_url,
100				type: 'POST',
101				dataType: 'json',
102				data: {
103					action: 'socialfeeds_load_more_instagram',
104					next_url: nextUrl,
105					load_count: parseInt($btn.data('load-count')) || 12,
106					show_reels: $btn.data('show-reels'),
107	    			show_feed_posts: $btn.data('show-feed-posts'),
108					layout: $btn.data('layout'),
109					padding: $btn.data('padding'),
110					cols: $btn.data('cols'),
111					aspect_ratio: $btn.data('aspect-ratio'),
112					caption_enabled: $btn.data('caption-enabled'),
113					likes_enabled: $btn.data('likes-enabled'),
114					comments_enabled: $btn.data('comments-enabled'),
115					views_enabled: $btn.data('views-enabled'),
116					hover_state: $btn.data('hover-state'),
117					play_mode: $btn.data('play-mode'),
118					show_play_icon: $btn.data('show-play-icon'),
119					nonce: socialfeeds_ajax.nonce
120				},
121				success: function (response) {
122
123					if (!response.success || !response.data) {
124						$btn.text('No More Posts').hide();
125						return;
126					}
127
128					if (response.data.html) {
129						$itemsContainer.append(response.data.html);
130						// If carousel, trigger resize to update dots/nav
131						if ($itemsContainer.hasClass('layout-carousel')) {
132							$(window).trigger('resize');
133						}
134					}
135
136					let new_loaded = loaded + response.data.count;
137					$btn.data('loaded', new_loaded).attr('data-loaded', new_loaded);
138
139					if (response.data.next) {
140						$btn.attr('data-next-url', response.data.next);
141						$btn.prop('disabled', false)
142							.removeClass('socialfeeds-loading')
143							.text(original_text);
144					} else {
145						$btn.text('No More Posts').hide();
146					}
147				},
148				error: function () {
149					console.error('SocialFeeds Instagram AJAX Error');
150					$btn.prop('disabled', false)
151						.removeClass('socialfeeds-loading')
152						.text('Error loading posts');
153				}
154			});
155		}
156		// ===== FACEBOOK LOAD MORE =====
157		else if (feedType === 'facebook') {
158			let original_text = $btn.text();
159			let $feed = $btn.closest('.socialfeeds-facebook-feed');
160			let $itemsContainer = $feed.find('.socialfeeds-facebook-inner');
161			let feedId = $btn.data('feed-id');
162			let loadCount = parseInt($btn.data('load-count')) || 9;
163			// Use Facebook cursor-based pagination — numeric offset causes duplicate posts
164			let afterCursor = $btn.attr('data-after-cursor') || '';
165
166			if (!afterCursor) {
167				$btn.text('No More Posts').hide();
168				return;
169			}
170
171			// Collect IDs of posts already on the page so the server can filter duplicates
172			let existingIds = [];
173			$itemsContainer.find('.socialfeeds-facebook-item[data-post-id]').each(function () {
174				let pid = $(this).attr('data-post-id');
175				if (pid) existingIds.push(pid);
176			});
177
178			$btn.prop('disabled', true).text('Loading...');
179
180			$.ajax({
181				url: socialfeeds_ajax.ajax_url,
182				type: 'POST',
183				dataType: 'json',
184				data: {
185					action: 'socialfeeds_load_more_facebook',
186					feed_id: feedId,
187					load_count: loadCount,
188					after_cursor: afterCursor,
189					existing_ids: existingIds,
190					nonce: socialfeeds_ajax.nonce
191				},
192				success: function (response) {
193					if (!response.success || !response.data || !response.data.html) {
194						$btn.text('No More Posts').hide();
195						return;
196					}
197
198					$itemsContainer.append(response.data.html);
199
200					// If carousel, trigger resize
201					if ($itemsContainer.hasClass('layout-carousel')) {
202						$(window).trigger('resize');
203					}
204
205					// Store the next cursor so the following click fetches the correct page
206					let nextCursor = response.data.next_cursor || '';
207					$btn.attr('data-after-cursor', nextCursor);
208
209					if (response.data.has_more && nextCursor) {
210						$btn.prop('disabled', false).text(original_text);
211					} else {
212						$btn.text('No More Posts').hide();
213					}
214				},
215				error: function () {
216					$btn.prop('disabled', false).text('Error loading posts');
217				}
218			});
219		}
220	});
221
222	init_insta_Modal();
223
224	// ===== INSTAGRAM CAROUSEL =====
225	function init_insta_Carousel() {
226		$('.socialfeeds-instagram-inner.layout-carousel, .socialfeeds-facebook-inner.layout-carousel').each(function () {
227			let $carousel = $(this);
228			let $feedWrapper = $carousel.closest('.socialfeeds-instagram-feed');
229
230			// Prevent double init
231			if ($feedWrapper.find('.socialfeeds-carousel-stage').length) return;
232
233			$carousel.wrap('<div class="socialfeeds-carousel-stage" style="position:relative; width:100%;"></div>');
234			let $stage = $carousel.parent();
235
236			let $nav = $('<div class="socialfeeds-carousel-nav">' +
237				'<button class="socialfeeds-carousel-btn prev" aria-label="Previous" type="button"><span class="dashicons dashicons-arrow-left-alt2"></span></button>' +
238				'<button class="socialfeeds-carousel-btn next" aria-label="Next" type="button"><span class="dashicons dashicons-arrow-right-alt2"></span></button>' +
239				'</div>');
240
241			$stage.append($nav);
242
243			let $dots = $('<div class="socialfeeds-carousel-dots"></div>');
244			$stage.after($dots);
245
246			function updateDots() {
247				$dots.empty();
248				let scrollW = $carousel[0].scrollWidth;
249				let clientW = $carousel[0].clientWidth;
250				if (clientW >= scrollW) {
251					$dots.hide();
252					$nav.hide();
253					return;
254				}
255
256				$dots.show();
257				$nav.show();
258
259				let pageCount = Math.ceil(scrollW / clientW);
260				for (let i = 0; i < pageCount; i++) {
261					let $d = $('<span class="socialfeeds-dot"></span>');
262					if (i === 0) $d.addClass('active');
263					$d.data('page', i);
264					$dots.append($d);
265				}
266			}
267
268			setTimeout(updateDots, 300);
269			$(window).on('resize', updateDots);
270
271			// Scroll Events
272			$nav.find('.prev').on('click', function (e) {
273				e.preventDefault();
274				$carousel.animate({ scrollLeft: $carousel.scrollLeft() - $carousel.width() }, 300, update_active_dot);
275			});
276
277			$nav.find('.next').on('click', function (e) {
278				e.preventDefault();
279				$carousel.animate({ scrollLeft: $carousel.scrollLeft() + $carousel.width() }, 300, update_active_dot);
280			});
281
282			$dots.on('click', '.socialfeeds-dot', function () {
283				let page = $(this).data('page');
284				$carousel.animate({ scrollLeft: page * $carousel.width() }, 400, update_active_dot);
285			});
286
287			function update_active_dot() {
288				let scroll_left = $carousel.scrollLeft();
289				let clientW = $carousel[0].clientWidth;
290				let page = Math.round(scroll_left / (clientW || 1));
291				$dots.find('.socialfeeds-dot').removeClass('active').eq(page).addClass('active');
292			}
293
294			$carousel.on('scroll', function () {
295				clearTimeout($carousel.data('scrollTimer'));
296				$carousel.data('scrollTimer', setTimeout(update_active_dot, 100));
297			});
298		});
299	}
300
301	init_insta_Carousel();
302});

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.