298 lines
11 KiB
JavaScript
298 lines
11 KiB
JavaScript
// Swiss Football Blocks Frontend JavaScript
|
|
(function($) {
|
|
'use strict';
|
|
|
|
// Team selector functionality for blocks
|
|
window.swiFootSelectTeam = function(teamId, blockType) {
|
|
if (!teamId) return;
|
|
|
|
// This could be enhanced to use AJAX for dynamic loading
|
|
const url = new URL(window.location);
|
|
url.searchParams.set('swi_foot_team_' + blockType, teamId);
|
|
window.location.href = url.toString();
|
|
};
|
|
|
|
// Auto-refresh functionality for events shortcodes
|
|
$(document).ready(function() {
|
|
initEventRefresh();
|
|
setupShortcodeHelpers();
|
|
});
|
|
|
|
/**
|
|
* Initialize event refresh polling for all match event shortcodes on page
|
|
*
|
|
* Finds all `.swi-foot-events[data-match-id][data-refresh]` elements and sets up
|
|
* automatic polling based on the configured refresh interval. Respects match status
|
|
* (does not update UI until match starts, stops polling when match ends).
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
function initEventRefresh() {
|
|
const $eventContainers = $('.swi-foot-events[data-match-id][data-refresh]');
|
|
|
|
if ($eventContainers.length === 0) return;
|
|
|
|
$eventContainers.each(function() {
|
|
const $container = $(this);
|
|
const matchId = $container.data('match-id');
|
|
const interval = parseInt($container.data('refresh')) || 30;
|
|
|
|
if (!matchId) return;
|
|
|
|
// Initial check: determine if match has started and if it should refresh
|
|
checkMatchStatusAndRefresh($container, matchId, interval);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize polling interval for match events
|
|
*
|
|
* Sets up a setInterval that periodically fetches the latest events for a match.
|
|
* Automatically clears the interval when the match ends.
|
|
*
|
|
* @param {jQuery} $container - jQuery element for the event container
|
|
* @param {string} matchId - ID of the match to fetch events for
|
|
* @param {number} interval - Refresh interval in seconds (e.g., 30)
|
|
* @returns {void}
|
|
*/
|
|
function checkMatchStatusAndRefresh($container, matchId, interval) {
|
|
fetchMatchEvents($container, matchId);
|
|
|
|
// Set up polling - will stop automatically once match ends
|
|
const pollInterval = setInterval(function() {
|
|
const hasEnded = $container.data('match-ended');
|
|
|
|
// Stop polling if match has ended
|
|
if (hasEnded) {
|
|
clearInterval(pollInterval);
|
|
return;
|
|
}
|
|
|
|
fetchMatchEvents($container, matchId);
|
|
}, interval * 1000);
|
|
}
|
|
|
|
/**
|
|
* Fetch latest match events from REST API
|
|
*
|
|
* Makes an authenticated request to `/wp-json/swi-foot/v1/events/{matchId}` to
|
|
* retrieve the current list of match events. Updates container data with match
|
|
* status (started/ended). Only updates the DOM if the match has started.
|
|
*
|
|
* @param {jQuery} $container - jQuery element for the event container
|
|
* @param {string} matchId - Match ID to fetch events for
|
|
* @returns {void}
|
|
*/
|
|
function fetchMatchEvents($container, matchId) {
|
|
const restUrl = window.swiFootRest ? window.swiFootRest.rest_url : '/wp-json';
|
|
const nonce = window.swiFootRest ? window.swiFootRest.rest_nonce : '';
|
|
|
|
// Get event order from data attribute
|
|
const eventOrder = $container.data('event-order') || 'dynamic';
|
|
|
|
// Build URL with event_order parameter
|
|
let url = restUrl + 'swi-foot/v1/events/' + encodeURIComponent(matchId);
|
|
if (eventOrder && eventOrder !== 'dynamic') {
|
|
url += '?event_order=' + encodeURIComponent(eventOrder);
|
|
}
|
|
|
|
fetch(url, {
|
|
method: 'GET',
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
'X-WP-Nonce': nonce
|
|
}
|
|
})
|
|
.then(function(resp) {
|
|
if (!resp.ok) throw new Error('Failed to fetch events');
|
|
return resp.json();
|
|
})
|
|
.then(function(data) {
|
|
if (!data) return;
|
|
|
|
// Track match status for polling control
|
|
$container.data('match-started', data.hasMatchStarted);
|
|
$container.data('match-ended', data.hasMatchEnded);
|
|
|
|
// Only update if match has started
|
|
if (!data.hasMatchStarted) {
|
|
return; // Don't update UI, match hasn't started yet
|
|
}
|
|
|
|
// Update events list
|
|
updateEventsList($container, data.events);
|
|
})
|
|
.catch(function(err) {
|
|
console.error('Error fetching match events:', err);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update the events timeline display with new events
|
|
*
|
|
* Renders an HTML list of match events from the API response, sorted newest first.
|
|
* Handles empty event lists with a localized message. Updates the `.events-timeline`
|
|
* element within the container.
|
|
*
|
|
* @param {jQuery} $container - jQuery element for the event container
|
|
* @param {Array<Object>} events - Array of event objects with matchMinute, eventTypeName, playerName, teamName
|
|
* @returns {void}
|
|
*/
|
|
function updateEventsList($container, events) {
|
|
const $timeline = $container.find('.events-timeline');
|
|
if ($timeline.length === 0) return;
|
|
|
|
// Build HTML for events
|
|
let html = '';
|
|
if (events && events.length > 0) {
|
|
events.forEach(function(event) {
|
|
html += '<div class="event-item">';
|
|
html += '<div class="event-time">' + (event.matchMinute || '') + '\'</div>';
|
|
html += '<div class="event-content">';
|
|
html += '<div class="event-type">' + (event.eventTypeName || '') + '</div>';
|
|
html += '<div class="event-details">';
|
|
if (event.playerName) {
|
|
html += '<span class="player">' + event.playerName + '</span>';
|
|
}
|
|
if (event.teamName) {
|
|
html += '<span class="team">(' + event.teamName + ')</span>';
|
|
}
|
|
html += '</div></div></div>';
|
|
});
|
|
} else {
|
|
html = '<p>' + (window.swiFootNoEvents || 'No events recorded yet.') + '</p>';
|
|
}
|
|
|
|
$timeline.html(html);
|
|
}
|
|
|
|
function setupShortcodeHelpers() {
|
|
// Add copy functionality to shortcode examples in admin
|
|
if ($('.shortcode-group code').length > 0) {
|
|
$('.shortcode-group code').each(function() {
|
|
const $code = $(this);
|
|
$code.css('cursor', 'pointer');
|
|
$code.attr('title', 'Click to copy shortcode');
|
|
|
|
$code.on('click', function() {
|
|
const shortcode = $(this).text();
|
|
copyToClipboard(shortcode);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function copyToClipboard(text) {
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
showNotification('Shortcode copied to clipboard!', 'success');
|
|
}).catch(function() {
|
|
fallbackCopyTextToClipboard(text);
|
|
});
|
|
} else {
|
|
fallbackCopyTextToClipboard(text);
|
|
}
|
|
}
|
|
|
|
function fallbackCopyTextToClipboard(text) {
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = text;
|
|
textArea.style.position = 'fixed';
|
|
textArea.style.left = '-999999px';
|
|
textArea.style.top = '-999999px';
|
|
document.body.appendChild(textArea);
|
|
textArea.focus();
|
|
textArea.select();
|
|
|
|
try {
|
|
document.execCommand('copy');
|
|
showNotification('Shortcode copied to clipboard!', 'success');
|
|
} catch (err) {
|
|
showNotification('Failed to copy shortcode', 'error');
|
|
}
|
|
|
|
document.body.removeChild(textArea);
|
|
}
|
|
|
|
function showNotification(message, type) {
|
|
const $notification = $('<div class="swi-foot-notification swi-foot-notification-' + type + '">' + message + '</div>');
|
|
|
|
$notification.css({
|
|
position: 'fixed',
|
|
top: '20px',
|
|
right: '20px',
|
|
padding: '10px 15px',
|
|
borderRadius: '4px',
|
|
color: '#fff',
|
|
fontSize: '14px',
|
|
zIndex: '10000',
|
|
opacity: '0',
|
|
transform: 'translateY(-20px)',
|
|
transition: 'all 0.3s ease'
|
|
});
|
|
|
|
if (type === 'success') {
|
|
$notification.css('backgroundColor', '#28a745');
|
|
} else {
|
|
$notification.css('backgroundColor', '#dc3545');
|
|
}
|
|
|
|
$('body').append($notification);
|
|
|
|
// Animate in
|
|
setTimeout(function() {
|
|
$notification.css({
|
|
opacity: '1',
|
|
transform: 'translateY(0)'
|
|
});
|
|
}, 100);
|
|
|
|
// Remove after 3 seconds
|
|
setTimeout(function() {
|
|
$notification.css({
|
|
opacity: '0',
|
|
transform: 'translateY(-20px)'
|
|
});
|
|
|
|
setTimeout(function() {
|
|
$notification.remove();
|
|
}, 300);
|
|
}, 3000);
|
|
}
|
|
|
|
// Initialize tooltips for match elements
|
|
$(document).ready(function() {
|
|
$('.swi-foot-match-container [title]').each(function() {
|
|
const $element = $(this);
|
|
$element.on('mouseenter', function() {
|
|
// Simple tooltip implementation
|
|
const title = $element.attr('title');
|
|
if (title) {
|
|
const $tooltip = $('<div class="swi-foot-tooltip">' + title + '</div>');
|
|
$tooltip.css({
|
|
position: 'absolute',
|
|
background: '#333',
|
|
color: '#fff',
|
|
padding: '5px 8px',
|
|
borderRadius: '4px',
|
|
fontSize: '12px',
|
|
zIndex: '1000',
|
|
whiteSpace: 'nowrap'
|
|
});
|
|
|
|
$('body').append($tooltip);
|
|
|
|
const rect = this.getBoundingClientRect();
|
|
$tooltip.css({
|
|
left: rect.left + (rect.width / 2) - ($tooltip.outerWidth() / 2),
|
|
top: rect.top - $tooltip.outerHeight() - 5
|
|
});
|
|
}
|
|
}).on('mouseleave', function() {
|
|
$('.swi-foot-tooltip').remove();
|
|
});
|
|
});
|
|
});
|
|
|
|
})(jQuery);
|