jQuery(document).ready(function($) { // Update player counts every 5 minutes function updatePlayerCounts() { const countElements = document.querySelectorAll('.fh-global-player-count'); if (!countElements.length) return; fetch(fh_ajax.ajax_url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ action: 'fh_get_global_player_count', nonce: fh_ajax.nonce }) }) .then(response => response.json()) .then(data => { countElements.forEach(element => { if (data.success && data.data.count > 0) { const formattedCount = new Intl.NumberFormat().format(data.data.count); const lastUpdated = new Date(data.data.timestamp * 1000); const timeAgo = timeSince(lastUpdated); element.innerHTML = ` ${formattedCount} ${fh_ajax.i18n.players_online} ${fh_ajax.i18n.updated_ago.replace('%s', timeAgo)} `; element.classList.remove('error'); } else { element.innerHTML = ` ${data.data?.error || fh_ajax.i18n.unable_to_fetch} `; element.classList.add('error'); } }); }) .catch(error => { console.error('Error updating player count:', error); countElements.forEach(element => { element.innerHTML = ` ${fh_ajax.i18n.update_error} `; element.classList.add('error'); }); }); } function timeSince(date) { const seconds = Math.floor((new Date() - date) / 1000); let interval = seconds / 31536000; if (interval > 1) return Math.floor(interval) + ' ' + fh_ajax.i18n.years; interval = seconds / 2592000; if (interval > 1) return Math.floor(interval) + ' ' + fh_ajax.i18n.months; interval = seconds / 86400; if (interval > 1) return Math.floor(interval) + ' ' + fh_ajax.i18n.days; interval = seconds / 3600; if (interval > 1) return Math.floor(interval) + ' ' + fh_ajax.i18n.hours; interval = seconds / 60; if (interval > 1) return Math.floor(interval) + ' ' + fh_ajax.i18n.minutes; return Math.floor(seconds) + ' ' + fh_ajax.i18n.seconds; } // Update player counts every 5 minutes setInterval(updatePlayerCounts, 300000); // Initial update document.addEventListener('DOMContentLoaded', updatePlayerCounts); // Add click handler for manual refresh document.addEventListener('click', function(e) { if (e.target.closest('.fh-global-player-count')) { const element = e.target.closest('.fh-global-player-count'); element.classList.add('updating'); updatePlayerCounts(); setTimeout(() => element.classList.remove('updating'), 1000); } }); // Improved copy code functionality $('.fh-copy-code').on('click touchstart', function(e) { if (e.type === 'touchstart') { e.preventDefault(); e.stopPropagation(); } var $button = $(this); var code = $button.data('code'); var postId = $button.data('post-id'); var nonce = $button.data('nonce'); var originalText = $button.text(); // Create a temporary input element var $tempInput = $(''); $('body').append($tempInput); $tempInput.val(code).select(); try { // Try to copy using both methods var successful = document.execCommand('copy'); if (!successful) { navigator.clipboard.writeText(code).then(function() { successful = true; }).catch(function() { successful = false; }); } if (successful) { // Update button text $button.text('Copied!'); // Track code copy $.ajax({ url: fh_ajax.ajax_url, type: 'POST', data: { action: 'track_code_copy', post_id: postId, nonce: nonce } }); } else { $button.text('Failed to copy'); } } catch (err) { console.error('Failed to copy code: ', err); $button.text('Failed to copy'); } // Remove temporary input $tempInput.remove(); // Reset button text after 2 seconds setTimeout(function() { $button.text(originalText); }, 2000); }); // Add tooltips for player counts $('.fh-player-count').hover( function() { $(this).append('
Click to refresh count
'); }, function() { $(this).find('.fh-tooltip').remove(); } ); // Manual refresh of player count $('.fh-player-count').on('click', function() { var $count = $(this); var postId = $count.closest('.fh-page-card').data('post-id'); $.ajax({ url: fh_ajax.ajax_url, type: 'POST', data: { action: 'get_island_player_count', post_id: postId, nonce: fh_ajax.nonce }, success: function(response) { if (response.success && response.data.count) { $count.find('.value').html(' ' + response.data.count.toLocaleString()); } } }); }); // Image gallery lightbox (if gallery exists) const galleryImages = document.querySelectorAll('.fh-island-gallery img'); if (galleryImages.length > 0) { galleryImages.forEach(image => { image.addEventListener('click', function() { const lightbox = document.createElement('div'); lightbox.className = 'fh-lightbox'; lightbox.innerHTML = `
${this.alt}
`; document.body.appendChild(lightbox); // Close lightbox lightbox.addEventListener('click', function(e) { if (e.target === lightbox || e.target.className === 'fh-lightbox-close') { lightbox.remove(); } }); }); }); } // Add smooth scrolling for filter form const filterForm = document.querySelector('.fh-filter-form'); if (filterForm) { filterForm.addEventListener('submit', function() { setTimeout(() => { window.scrollTo({ top: document.querySelector('.fh-islands-grid').offsetTop - 100, behavior: 'smooth' }); }, 100); }); } // Add loading state for filter submissions const filterSubmit = document.querySelector('.fh-filter-submit'); if (filterSubmit) { filterSubmit.addEventListener('click', function() { this.classList.add('loading'); this.textContent = 'Filtering...'; }); } // Add hover effect for island cards const islandCards = document.querySelectorAll('.fh-island-card'); islandCards.forEach(card => { card.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-5px)'; }); card.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; }); }); // Handle island interactions const interactionButtons = document.querySelectorAll('.interaction-buttons button'); interactionButtons.forEach(button => { button.addEventListener('click touchstart', function(e) { if (e.type === 'touchstart') { e.preventDefault(); e.stopPropagation(); } const postId = this.getAttribute('data-post-id'); const nonce = this.getAttribute('data-nonce'); const action = this.classList.contains('like-button') ? 'like' : (this.classList.contains('dislike-button') ? 'dislike' : 'favorite'); const $button = $(this); // Disable button during request $button.prop('disabled', true); $.ajax({ url: fh_ajax.ajax_url, type: 'POST', data: { action: 'update_island_interaction', post_id: postId, interaction: action, nonce: nonce }, success: function(response) { if (response.success) { // Update button state $button.toggleClass('active'); // Update count display const $countElement = $button.find('.count'); const newCount = response.data.count; $countElement.text(newCount.toLocaleString()); // Update corresponding metric if it's favorites if (action === 'favorite') { $('#favorites-count').text(newCount.toLocaleString()); } // Update other buttons if needed if (action === 'like') { $('.dislike-button').removeClass('active'); } else if (action === 'dislike') { $('.like-button').removeClass('active'); } } }, error: function(jqXHR, textStatus, errorThrown) { console.error('AJAX Request Failed:', textStatus, errorThrown); }, complete: function() { // Re-enable button after request $button.prop('disabled', false); } }); }); }); // Add scroll-to-top button // Create scroll-to-top button const scrollButton = document.createElement('button'); scrollButton.className = 'scroll-to-top'; scrollButton.innerHTML = '↑'; scrollButton.setAttribute('aria-label', 'Scroll to top'); document.body.appendChild(scrollButton); // Show/hide scroll button based on scroll position window.addEventListener('scroll', function() { if (window.pageYOffset > 300) { scrollButton.classList.add('visible'); } else { scrollButton.classList.remove('visible'); } }); // Scroll to top when clicked scrollButton.addEventListener('click', function() { window.scrollTo({ top: 0, behavior: 'smooth' }); }); // Add loading state to grids during AJAX operations const grids = document.querySelectorAll('.fh-islands-grid'); grids.forEach(grid => { grid.addEventListener('loading', () => { grid.classList.add('loading'); }); grid.addEventListener('loaded', () => { grid.classList.remove('loading'); }); }); // Add keyboard navigation support document.addEventListener('keydown', function(e) { if (e.key === 'Tab') { document.body.classList.add('keyboard-navigation'); } }); document.addEventListener('mousedown', function() { document.body.classList.remove('keyboard-navigation'); }); // Carousel functionality const carousels = document.querySelectorAll('.fh-carousel-container'); carousels.forEach(container => { const carousel = container.querySelector('.fh-carousel'); const prevBtn = container.querySelector('.fh-carousel-prev'); const nextBtn = container.querySelector('.fh-carousel-next'); const cards = carousel.querySelectorAll('.fh-page-card'); if (cards.length === 0) return; const gap = parseInt(getComputedStyle(carousel).gap); const cardWidth = cards[0].offsetWidth; const cardsPerView = window.innerWidth <= 768 ? (window.innerWidth <= 480 ? 1 : 2) : 3; let currentPosition = 0; const maxPosition = Math.max(0, cards.length - cardsPerView); function updateButtons() { prevBtn.style.display = currentPosition <= 0 ? 'none' : 'flex'; nextBtn.style.display = currentPosition >= maxPosition ? 'none' : 'flex'; } function moveCarousel() { const offset = currentPosition * (cardWidth + gap); carousel.style.transform = `translateX(-${offset}px)`; updateButtons(); } prevBtn.addEventListener('click', () => { if (currentPosition > 0) { currentPosition--; moveCarousel(); } }); nextBtn.addEventListener('click', () => { if (currentPosition < maxPosition) { currentPosition++; moveCarousel(); } }); // Handle window resize let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(() => { const newCardWidth = cards[0].offsetWidth; const newCardsPerView = window.innerWidth <= 768 ? (window.innerWidth <= 480 ? 1 : 2) : 3; const newMaxPosition = Math.max(0, cards.length - newCardsPerView); if (currentPosition > newMaxPosition) { currentPosition = newMaxPosition; } moveCarousel(); }, 250); }); // Initialize updateButtons(); moveCarousel(); }); }); // Add focus styles for keyboard navigation const style = document.createElement('style'); style.textContent = ` .keyboard-navigation *:focus { outline: 2px solid var(--border-color); outline-offset: 2px; } `; document.head.appendChild(style);