// Wait for DOM to be ready
(function() {
'use strict';
// Ensure scoresConfig is available
if (typeof window.scoresConfig === 'undefined') {
console.warn('scoresConfig not found');
return;
}
const config = window.scoresConfig;
function datePicker() {
return {
init() {
this.fp = flatpickr(this.$refs.flatpickr, {
dateFormat: "Y-m-d",
defaultDate: config.selectedDate,
onChange: (selectedDates, dateStr) => {
const url = new URL(window.location.href);
url.searchParams.set('date', dateStr);
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
window.location.href = url.toString();
}
});
// Populate search field with the previously entered value
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
const searchParams = new URLSearchParams(window.location.search);
const searchValue = searchParams.get('search');
if (searchValue) {
document.getElementById('search-input').value = decodeURIComponent(searchValue);
}
},
openCalendar() {
this.fp.open();
},
redirectToDate(url) {
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
window.location.href = url;
}
}
}
function searchRedirect(event) {
event.preventDefault();
const searchInput = document.getElementById('search-input').value;
const url = new URL(window.location.href);
url.searchParams.set('search', encodeURIComponent(searchInput));
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
window.location.href = url.toString();
}
function scoreViewToggle() {
return {
view: localStorage.getItem('scoresView') || 'grid',
changeView(view) {
this.view = view;
localStorage.setItem('scoresView', view);
},
loadEditGameForm(gameId) {
const container = document.getElementById('edit-game-form-container');
if (!container) return;
// Show loading state
container.innerHTML = '
Loading...
';
// Load the form via AJAX
fetch(config.ajaxUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'load_edit_game_form',
game_id: gameId,
nonce: config.loadEditGameFormNonce
})
})
.then(response => response.text())
.then(html => {
container.innerHTML = html;
if (typeof Alpine !== 'undefined') {
Alpine.initTree(container);
}
})
.catch(error => {
console.error('Error loading edit game form:', error);
container.innerHTML = 'Error loading form. Please try again.
';
});
}
}
}
function scoresData() {
return {
...scoreViewToggle(),
showGameModal: null,
filters: {
class: config.urlFilters.class || [],
conference: config.urlFilters.conference || [],
section: config.urlFilters.section || [],
district: config.urlFilters.district || [],
hasStream: config.urlFilters.hasStream || false,
isTop25Matchup: config.urlFilters.isTop25Matchup || false
},
init() {
this.view = localStorage.getItem('scoresView') || 'grid';
this.$watch('showGameModal', (gameId) => {
if (gameId) {
loadEditGameForm(gameId);
}
});
// Watch filters and apply filtering + sorting
this.$watch('filters', () => {
this.filterAndSortGames();
this.updateURL();
}, { deep: true });
// Handle browser back/forward buttons
window.addEventListener('popstate', () => {
this.loadFiltersFromURL();
});
// Initial sort on page load
this.$nextTick(() => {
this.filterAndSortGames();
});
},
loadFiltersFromURL() {
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
const url = new URL(window.location.href);
this.filters = {
class: url.searchParams.getAll('class'),
conference: url.searchParams.getAll('conference'),
section: url.searchParams.getAll('section'),
district: url.searchParams.getAll('district'),
hasStream: url.searchParams.get('stream') === '1',
isTop25Matchup: url.searchParams.get('top25matchup') === '1'
};
},
updateURL() {
// Safe internal redirect to same domain
// eslint-disable-next-line WordPressVIPMinimum.JS.Window.location
const url = new URL(window.location.href);
// Remove existing filter params
['class', 'conference', 'section', 'district', 'stream', 'top25matchup'].forEach(key => {
url.searchParams.delete(key);
});
// Add current filter values
Object.keys(this.filters).forEach(key => {
if (key === 'hasStream') {
// Add stream param if checkbox is checked
if (this.filters.hasStream) {
url.searchParams.set('stream', '1');
}
} else if (key === 'isTop25Matchup') {
// Add top25matchup param if checkbox is checked
if (this.filters.isTop25Matchup) {
url.searchParams.set('top25matchup', '1');
}
} else if (this.filters[key].length > 0) {
this.filters[key].forEach(value => {
// Safe: appending URL parameters, not injecting HTML
// eslint-disable-next-line WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
url.searchParams.append(key, value);
});
}
});
// Update URL without page reload
window.history.pushState({}, '', url);
},
hasActiveFilters() {
return this.filters.class.length > 0 ||
this.filters.conference.length > 0 ||
this.filters.section.length > 0 ||
this.filters.district.length > 0 ||
this.filters.hasStream ||
this.filters.isTop25Matchup;
},
clearFilters() {
this.filters = {
class: [],
conference: [],
section: [],
district: [],
hasStream: false,
isTop25Matchup: false
};
// URL will be updated by the watcher
},
filterAndSortGames() {
const gridContainer = document.querySelector('#scores-grid');
const tableBody = document.querySelector('#scores-table tbody');
const container = gridContainer || tableBody;
if (!container) return;
const gameElements = Array.from(container.children).filter(el =>
el.classList.contains('game-row') || el.classList.contains('game-card')
);
// Filter games
gameElements.forEach(gameEl => {
const shouldShow = this.shouldShowGame(gameEl);
gameEl.style.display = shouldShow ? '' : 'none';
});
// Sort visible games: Top 25 matchups first, then single Top 25 team, then others
const visibleGames = gameElements.filter(el => el.style.display !== 'none');
visibleGames.sort((a, b) => {
const aTop25Matchup = a.dataset.top25Matchup === 'true';
const bTop25Matchup = b.dataset.top25Matchup === 'true';
const aHasTop25 = a.dataset.hasTop25 === 'true';
const bHasTop25 = b.dataset.hasTop25 === 'true';
// Both are Top 25 matchups or neither - maintain order
if (aTop25Matchup && bTop25Matchup) return 0;
if (!aTop25Matchup && !bTop25Matchup) {
// Check single Top 25 team
if (aHasTop25 && bHasTop25) return 0;
if (aHasTop25) return -1;
if (bHasTop25) return 1;
return 0;
}
// One is Top 25 matchup
return aTop25Matchup ? -1 : 1;
});
// Re-append in sorted order
visibleGames.forEach(el => container.appendChild(el));
// Update game count
this.updateGameCount(visibleGames.length);
},
shouldShowGame(gameEl) {
// If no filters active, show all games
if (!this.hasActiveFilters()) return true;
// Helper function to check if a filter matches home/away values
const matchesFilter = (filterType) => {
const filterValues = this.filters[filterType];
if (filterValues.length === 0) return true;
const homeKey = `home${filterType.charAt(0).toUpperCase() + filterType.slice(1)}`;
const awayKey = `away${filterType.charAt(0).toUpperCase() + filterType.slice(1)}`;
return filterValues.some(value => {
const homeValue = gameEl.dataset[homeKey] || '';
const awayValue = gameEl.dataset[awayKey] || '';
return homeValue === value || awayValue === value;
});
};
// Check each filter type
const classMatch = matchesFilter('class');
const conferenceMatch = matchesFilter('conference');
const sectionMatch = matchesFilter('section');
const districtMatch = matchesFilter('district');
// Check stream filter
const streamMatch = !this.filters.hasStream || gameEl.dataset.hasStream === 'true';
// Check Top 25 Matchup filter
const top25MatchupMatch = !this.filters.isTop25Matchup || gameEl.dataset.top25Matchup === 'true';
return classMatch && conferenceMatch && sectionMatch && districtMatch && streamMatch && top25MatchupMatch;
},
updateGameCount(count) {
const countDisplay = document.querySelector('.game-count-display');
if (countDisplay) {
countDisplay.textContent = `${count} ${count === 1 ? 'game' : 'games'}`;
}
}
}
}
function loadEditGameForm(gameId) {
const container = document.getElementById('edit-game-form-container');
console.log('container', container);
if (!container) return;
// Prevent duplicate calls
if (window.loadingForm) return;
window.loadingForm = true;
// Show loading state
container.innerHTML = 'Loading...
';
const formData = new URLSearchParams({
action: 'loadEditGameForm',
game_id: gameId,
nonce: config.loadEditGameFormNonce,
// Safe: passing URL as parameter, not injecting HTML
// eslint-disable-next-line WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
current_url: window.location.href
});
fetch(config.ajaxUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData
})
.then(response => response.text())
.then(html => {
// Safe: setting innerHTML, not injecting HTML
// eslint-disable-next-line WordPressVIPMinimum.JS.InnerHTML.Found
container.innerHTML = html;
// Initialize ACF form after AJAX load
if (typeof acf !== 'undefined') {
const $form = jQuery(container).find('.acf-form');
if ($form.length) {
acf.doAction('append', $form);
setTimeout(() => {
acf.doAction('ready', $form);
acf.doAction('show_field', $form);
}, 100);
}
}
window.loadingForm = false;
})
.catch(error => {
console.error('Error loading edit game form:', error);
container.innerHTML = 'Error loading form. Please try again.
';
window.loadingForm = false;
});
}
function gameFormData() {
return {
confirmDelete: false,
successMessage: null,
loading: false,
submitting: false,
handleFormSubmit(event) {
if (this.submitting) {
event.preventDefault();
return;
}
this.submitting = true;
const submitButton = event.target.querySelector('input[type="submit"]');
if (submitButton) {
submitButton.disabled = true;
submitButton.value = 'Updating...';
submitButton.classList.add('opacity-50', 'cursor-not-allowed');
}
}
};
}
function deleteGame(gameID, state) {
state.confirmDelete = false;
state.loading = true;
state.successMessage = null;
fetch(`${window.wpApiSettings.root}wp/v2/games/${gameID}?force=false`, {
method: 'DELETE',
headers: {
'X-WP-Nonce': window.wpApiSettings.nonce,
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(data => {
if (data.deleted || data.status === 'trash') {
state.successMessage = 'Game deleted successfully, refreshing page...';
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
alert(data.data || 'Could not trash game.');
state.loading = false;
}
})
.catch(() => {
alert('Request failed.');
state.loading = false;
});
}
// Make functions globally available for Alpine.js
window.datePicker = datePicker;
window.searchRedirect = searchRedirect;
window.scoreViewToggle = scoreViewToggle;
window.scoresData = scoresData;
window.loadEditGameForm = loadEditGameForm;
window.gameFormData = gameFormData;
window.deleteGame = deleteGame;
})();
;
const prevIcon = '';
const nextIcon = '';
function featureSlider() {
return {
sliderInitialized: false,
sliderInView: false,
initSlider() {
const self = this; // Store reference for use in callbacks
// Use IntersectionObserver to detect when slider container is in view
const sliderContainer = document.querySelector('.feature-slider');
if (!sliderContainer) return;
const sliderObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !self.sliderInView) {
self.sliderInView = true;
// If slider is already initialized, load images immediately
if (self.sliderInitialized) {
self.lazyLoadVisibleSlides();
}
}
}, {
rootMargin: '300px', // Start loading well before slider is visible
threshold: 0
});
sliderObserver.observe(sliderContainer);
Alpine.nextTick(() => {
const $slider = jQuery('.feature-slider');
$slider.slick({
arrows: true,
prevArrow: '',
nextArrow: '',
autoplay: true,
autoplaySpeed: 6000,
infinite: false,
speed: 300,
slidesToShow: 2.5,
slidesToScroll: 1,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
}
},
{
breakpoint: 768,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
}
}
]
});
self.sliderInitialized = true;
// Load images immediately if slider is already in view
if (self.sliderInView) {
self.lazyLoadVisibleSlides();
}
// Load images when slider initializes
$slider.on('init', function () {
self.lazyLoadVisibleSlides();
});
// Preload images BEFORE slide change to ensure they're ready
$slider.on('beforeChange', function () {
self.lazyLoadVisibleSlides();
});
// Also load on afterChange as backup
$slider.on('afterChange', function () {
self.lazyLoadVisibleSlides();
});
});
},
lazyLoadVisibleSlides() {
const $slider = jQuery('.feature-slider');
if (!$slider.length || !$slider.slick('getSlick')) return;
try {
const currentIndex = $slider.slick('slickCurrentSlide') || 0;
const slidesToShow = $slider.slick('getSlick').options.slidesToShow || 1;
const totalSlides = $slider.slick('getSlick').slideCount || 0;
// Load images for visible slides plus 3 ahead for aggressive preloading
const slidesToLoad = Math.ceil(slidesToShow) + 3;
for (let i = 0; i < slidesToLoad; i++) {
const slideIndex = currentIndex + i;
if (slideIndex >= totalSlides) break;
const slideElement = $slider.find('[data-slide-index="' + slideIndex + '"]').first()[0];
if (!slideElement) continue;
// Access Alpine component data to trigger lazy loading
if (slideElement._x_dataStack && slideElement._x_dataStack.length > 0) {
const alpineData = slideElement._x_dataStack[0];
if (alpineData && typeof alpineData.loadBackground === 'function' && !alpineData.loaded) {
alpineData.loadBackground();
}
}
}
} catch (e) {
console.warn('Error loading slider images:', e);
}
}
}
};