| Server IP : 74.208.236.79 / Your IP : 216.73.217.19 Web Server : Apache System : Linux infongp-us50 4.4.400-icpu-108 #2 SMP Wed Feb 11 10:12:42 UTC 2026 x86_64 User : u93192080 ( 6162215) PHP Version : 8.4.22 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /homepages/45/d732875416/htdocs/clickandbuilds/IronWyvern/ |
Upload File : |
(function () {
// --- Global State & Element Caching ---
const dynamicFieldsContainer = document.getElementById('dynamic-fields-container');
const makePairingsBtn = document.getElementById('make-pairings-btn');
const pairingsContainer = document.getElementById('pairings-container');
const standingsContainer = document.getElementById('standings-container');
const resetBtn = document.getElementById('reset-btn');
const titleInput = document.getElementById('title-input');
const dateInput = document.getElementById('date-input');
const roundsSelect = document.getElementById('rounds-select');
const downloadBtn = document.getElementById('download-btn');
const fileInput = document.getElementById('file-input');
const setupContent = document.getElementById('setup-content');
const setupToggleHeader = document.getElementById('setup-toggle-header');
const setupToggleIcon = document.getElementById('setup-toggle-icon');
const modeSelect = document.getElementById('mode-select');
let pairings = {};
let standings = [];
let currentRound = 0;
let podIdCounter = 0;
// --- Modal UI for Alerts and Confirmation ---
function createModal(title, message, type = 'alert', callback = () => {}) {
let modal = document.getElementById('custom-modal');
if (!modal) {
modal = document.createElement('div');
modal.id = 'custom-modal';
modal.className = 'fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center p-4 z-50 hidden';
document.body.appendChild(modal);
}
const modalContent = document.createElement('div');
modalContent.className = 'bg-gray-800 p-6 rounded-lg shadow-2xl w-full max-w-sm';
modalContent.innerHTML = `
<h3 id="modal-title" class="text-xl font-bold mb-4 text-white">${title}</h3>
<p id="modal-message" class="text-gray-300 mb-6">${message}</p>
<div id="modal-buttons" class="flex justify-end gap-2"></div>
`;
modal.innerHTML = '';
modal.appendChild(modalContent);
const buttonsContainer = modalContent.querySelector('#modal-buttons');
if (type === 'confirm') {
const cancelButton = document.createElement('button');
cancelButton.className = 'px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors';
cancelButton.textContent = 'Cancel';
cancelButton.addEventListener('click', () => {
modal.classList.add('hidden');
callback(false);
});
buttonsContainer.appendChild(cancelButton);
}
const okButton = document.createElement('button');
okButton.className = 'px-4 py-2 bg-orange-500 text-white rounded-lg hover:bg-orange-600 transition-colors';
okButton.textContent = 'OK';
okButton.addEventListener('click', () => {
modal.classList.add('hidden');
if (type === 'alert') {
callback();
} else {
callback(true);
}
});
buttonsContainer.appendChild(okButton);
modal.classList.remove('hidden');
}
// --- Utility Functions ---
function updateMakePairingsButton() {
const playerInputs = dynamicFieldsContainer.querySelectorAll('.player-input');
const validPlayers = Array.from(playerInputs).filter(input => input.value.trim() !== '' && isValidName(input.value));
const playerCount = validPlayers.length;
const mode = modeSelect.value;
let requiredPlayers;
if (mode === '1v1') {
requiredPlayers = 4;
} else if (mode === 'pod') {
requiredPlayers = 5;
}
makePairingsBtn.disabled = playerCount < requiredPlayers;
makePairingsBtn.classList.toggle('opacity-50', makePairingsBtn.disabled);
makePairingsBtn.classList.toggle('cursor-not-allowed', makePairingsBtn.disabled);
}
function updateDeleteButtonVisibility() {
const playerRows = document.querySelectorAll('.player-row');
if (playerRows.length <= 1) {
playerRows[0].querySelector('.remove-player-btn').style.visibility = 'hidden';
} else {
playerRows.forEach(row => {
row.querySelector('.remove-player-btn').style.visibility = 'visible';
});
}
}
// New function to enable/disable setup inputs
function toggleSetupInputs(isDisabled) {
titleInput.disabled = isDisabled;
dateInput.disabled = isDisabled;
modeSelect.disabled = isDisabled;
roundsSelect.disabled = isDisabled;
const playerInputs = dynamicFieldsContainer.querySelectorAll('.player-input');
playerInputs.forEach(input => {
input.disabled = isDisabled;
});
const removeButtons = dynamicFieldsContainer.querySelectorAll('.remove-player-btn');
removeButtons.forEach(button => {
button.disabled = isDisabled;
button.classList.toggle('opacity-50', isDisabled);
button.classList.toggle('cursor-not-allowed', isDisabled);
button.classList.toggle('hidden', isDisabled);
});
// Toggle the make pairings button's disabled state
makePairingsBtn.disabled = isDisabled;
makePairingsBtn.classList.toggle('opacity-50', isDisabled);
makePairingsBtn.classList.toggle('cursor-not-allowed', isDisabled);
}
function createPlayerInputRow() {
const playerRow = document.createElement('div');
playerRow.className = 'player-row flex items-center gap-2';
const input = document.createElement('input');
input.type = 'text';
input.className = 'player-input flex-1 p-3 rounded-lg border-2 border-gray-600 bg-gray-800 text-white placeholder-gray-400 focus:outline-none focus:border-orange-500 transition-colors duration-200 shadow-inner';
input.placeholder = 'Player Name';
const removeButton = document.createElement('button');
removeButton.className = 'remove-player-btn';
removeButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-minus"><path d="M5 12h14"/></svg>`;
playerRow.appendChild(input);
playerRow.appendChild(removeButton);
return playerRow;
}
function isValidName(name) {
const regex = /^[a-zA-Z0-9\s]+$/;
return regex.test(name);
}
function getPlayers() {
const playerInputs = document.querySelectorAll('.player-input');
return Array.from(playerInputs)
.map(input => input.value.trim())
.filter(name => name !== '' && isValidName(name));
}
// --- Pairing Logic ---
// 1v1 Swiss System pairings
function make1v1Pairings() {
const sortedPlayers = [...standings].sort((a, b) => {
if (b.points !== a.points) return b.points - a.points;
return (b.tiebreaker || 0) - (a.tiebreaker || 0);
});
const playerList = sortedPlayers.map(p => ({
name: p.name,
played: p.played,
points: p.points,
byes: p.byes
}));
const currentPairings = [];
const pairedPlayers = new Set();
let byePlayer = null;
let byePairing = null;
if (playerList.length % 2 !== 0) {
let eligibleForBye = playerList.filter(p => p.byes === 0);
if (eligibleForBye.length === 0) {
eligibleForBye = playerList;
}
byePlayer = eligibleForBye[eligibleForBye.length - 1];
byePairing = [byePlayer.name, 'Bye'];
pairedPlayers.add(byePlayer.name);
byePlayer.byes++;
}
for (let i = 0; i < playerList.length; i++) {
const playerA = playerList[i];
if (pairedPlayers.has(playerA.name)) continue;
let paired = false;
for (let j = i + 1; j < playerList.length; j++) {
const playerB = playerList[j];
if (pairedPlayers.has(playerB.name)) continue;
const hasPlayed = playerA.played.some(match => match === playerB.name);
if (!hasPlayed) {
currentPairings.push([playerA.name, playerB.name]);
pairedPlayers.add(playerA.name);
pairedPlayers.add(playerB.name);
paired = true;
break;
}
}
if (!paired) {
for (let j = i + 1; j < playerList.length; j++) {
const playerB = playerList[j];
if (!pairedPlayers.has(playerB.name)) {
currentPairings.push([playerA.name, playerB.name]);
pairedPlayers.add(playerA.name);
pairedPlayers.add(playerB.name);
break;
}
}
}
}
// Add the bye pairing to the end of the list
if (byePairing) {
currentPairings.push(byePairing);
}
return currentPairings;
}
// Pod Pairing Logic (updated)
function makePodPairings() {
const playerNames = getPlayers();
const numPlayers = playerNames.length;
let pairings = [];
// Handle the specific case for exactly 5 players
if (numPlayers === 5) {
return [playerNames];
}
// Handle the general case for 3 and 4 player pairings
if (numPlayers < 3) {
console.error("Not enough players for a valid pairing (minimum 3).");
return [];
}
// Shuffle the players to ensure random pods
const shuffledPlayers = [...playerNames].sort(() => Math.random() - 0.5);
// Determine the number of 4-player and 3-player pods
let numFours = 0;
let numThrees = 0;
// Greedy approach: Maximize 4-player pods first
for (let i = Math.floor(numPlayers / 4); i >= 0; i--) {
const remaining = numPlayers - (i * 4);
if (remaining % 3 === 0) {
numFours = i;
numThrees = remaining / 3;
break;
}
}
// If no combination is found, it's an invalid number of players
if ((numFours * 4 + numThrees * 3) !== numPlayers) {
console.error(`Cannot form valid 3 or 4 player pods with ${numPlayers} players.`);
return [];
}
// Create the 4-player pods
let currentIndex = 0;
for (let i = 0; i < numFours; i++) {
pairings.push(shuffledPlayers.slice(currentIndex, currentIndex + 4));
currentIndex += 4;
}
// Create the 3-player pods
for (let i = 0; i < numThrees; i++) {
pairings.push(shuffledPlayers.slice(currentIndex, currentIndex + 3));
currentIndex += 3;
}
return pairings;
}
function updateStandings() {
// Reset points and tiebreakers for recalculation from the start
standings.forEach(player => {
player.points = 0;
player.tiebreaker = 0;
player.byes = 0;
player.played = [];
});
// Loop through all past rounds to update standings
for (let r = 1; r <= currentRound; r++) {
const roundPairings = pairings[r];
roundPairings.forEach(pairing => {
if (pairing.type === '1v1') {
if (pairing.players[1] === 'Bye') {
const player = standings.find(p => p.name === pairing.players[0]);
if (player) {
player.points += 1;
player.byes++;
}
} else {
const player1 = standings.find(p => p.name === pairing.players[0]);
const player2 = standings.find(p => p.name === pairing.players[1]);
if (player1 && player2) {
if (pairing.result === 'win') {
const winner = standings.find(p => p.name === pairing.winner);
if (winner) winner.points += 1;
} else if (pairing.result === 'draw') {
player1.points += 0.5;
player2.points += 0.5;
}
}
// Update 'played' list for 1v1
if (player1) player1.played.push(player2.name);
if (player2) player2.played.push(player1.name);
}
} else if (pairing.type === 'pod') {
const podPlayers = pairing.players.map(name => standings.find(p => p.name === name)).filter(p => p);
if (pairing.result === 'win') {
const winner = standings.find(p => p.name === pairing.winner);
if (winner) winner.points += 1;
} else if (pairing.result === 'draw') {
pairing.winners.forEach(winnerName => {
const winner = standings.find(p => p.name === winnerName);
if (winner) winner.points += 0.5;
});
}
// Update 'played' list for pods (each player played against everyone else in the pod)
podPlayers.forEach(p1 => {
podPlayers.forEach(p2 => {
if (p1 && p2 && p1.name !== p2.name) {
p1.played.push(p2.name);
}
});
});
}
});
}
// Recalculate tiebreakers after updating all points
standings.forEach(player => {
player.tiebreaker = 0;
const playedOpponents = new Set(player.played);
playedOpponents.forEach(opponentName => {
const opponent = standings.find(p => p.name === opponentName);
if (opponent) {
player.tiebreaker += opponent.points;
}
});
});
renderStandings();
}
// --- Rendering Functions ---
function renderPairings(currentRoundPairings) {
pairingsContainer.innerHTML = '';
const mode = modeSelect.value;
if (currentRoundPairings.length === 0) {
pairingsContainer.innerHTML = `<p class="text-center text-red-400">Not enough players for a new round.</p>`;
return;
}
const roundHeader = document.createElement('div');
roundHeader.className = 'flex items-center justify-between p-4 bg-gray-700 rounded-lg mb-4';
roundHeader.innerHTML = `<h2 class="text-xl font-semibold text-orange-400">Round ${currentRound} Pairings</h2>`;
pairingsContainer.appendChild(roundHeader);
const pairingsList = document.createElement('div');
pairingsList.className = 'space-y-4';
currentRoundPairings.forEach((pairing) => {
const pairingItem = document.createElement('div');
pairingItem.className = 'pairing-item p-4 bg-gray-700 rounded-lg flex flex-col sm:flex-row items-center justify-center gap-4 shadow-inner';
const playerButtonsContainer = document.createElement('div');
playerButtonsContainer.className = 'flex flex-wrap justify-center gap-2 w-full';
playerButtonsContainer.dataset.podId = pairing.podId;
if (mode === '1v1') {
const [player1, player2] = pairing.players;
if (player2 === 'Bye') {
// This is a BYE match
pairingItem.classList.remove('bg-gray-700');
pairingItem.classList.add('bye-pairing');
pairingItem.innerHTML = `
<span class="text-lg font-semibold">${player1} has a BYE</span>
<div class="flex items-center space-x-2">
<button class="bg-green-500 text-white font-bold py-2 px-4 rounded-xl shadow-lg bye-button transition-colors duration-200">
Will receive a win
</button>
</div>
`;
} else {
// This is a regular 1v1 match
let winnerBtnClass = '';
let loserBtnClass = '';
let centerText = 'vs';
if (pairing) {
if (pairing.result === 'win') {
if (pairing.winner === player1) {
winnerBtnClass = 'selected-win';
} else {
loserBtnClass = 'selected-win';
}
} else if (pairing.result === 'draw') {
winnerBtnClass = 'selected-draw';
loserBtnClass = 'selected-draw';
centerText = 'Draw';
}
}
pairingItem.innerHTML = `
<div class="flex flex-col sm:flex-row items-center justify-center gap-2 sm:gap-4 w-full">
<button class="win-btn ${winnerBtnClass}" data-player="${player1}" data-opponent="${player2}">${player1}</button>
<span class="text-lg font-semibold text-gray-400">${centerText}</span>
<button class="win-btn ${loserBtnClass}" data-player="${player2}" data-opponent="${player1}">${player2}</button>
</div>
`;
}
} else if (mode === 'pod') {
pairing.players.forEach(player => {
const button = document.createElement('button');
button.textContent = player;
button.className = 'pod-btn';
button.dataset.player = player;
if (pairing && pairing.winners && pairing.winners.includes(player)) {
if (pairing.result === 'win') {
button.classList.add('selected-win');
} else if (pairing.result === 'draw') {
button.classList.add('selected-draw');
}
}
playerButtonsContainer.appendChild(button);
});
pairingItem.appendChild(playerButtonsContainer);
}
pairingsList.appendChild(pairingItem);
});
pairingsContainer.appendChild(pairingsList);
const submitRoundBtn = document.createElement('button');
submitRoundBtn.id = 'submit-round-btn';
submitRoundBtn.className = 'w-full bg-orange-500 text-white font-semibold py-3 px-6 rounded-lg shadow-md mt-4 transition-colors duration-200 opacity-50 cursor-not-allowed';
submitRoundBtn.textContent = 'Submit Round Results';
submitRoundBtn.disabled = true;
pairingsContainer.appendChild(submitRoundBtn);
pairingsContainer.classList.remove('hidden');
}
function renderStandings() {
standingsContainer.innerHTML = '';
const standingsHeader = document.createElement('div');
standingsHeader.className = 'flex items-center justify-between p-4 bg-gray-700 rounded-lg mb-4';
standingsHeader.innerHTML = `<h2 id="standings-title" class="text-xl font-semibold text-orange-400">Standings</h2>`;
standingsContainer.appendChild(standingsHeader);
const table = document.createElement('table');
table.className = 'min-w-full leading-normal';
table.innerHTML = `
<thead>
<tr>
<th class="px-5 py-3 border-b-2 border-gray-600 !text-white text-left text-xs font-semibold uppercase tracking-wider">Rank</th>
<th class="px-5 py-3 border-b-2 border-gray-600 !text-white text-left text-xs font-semibold uppercase tracking-wider">Name</th>
<th class="px-5 py-3 border-b-2 border-gray-600 !text-white text-left text-xs font-semibold uppercase tracking-wider">Points</th>
<th class="px-5 py-3 border-b-2 border-gray-600 !text-white text-left text-xs font-semibold uppercase tracking-wider">Tiebreaker</th>
</tr>
</thead>
<tbody></tbody>
`;
const tbody = table.querySelector('tbody');
standings.sort((a, b) => {
if (b.points !== a.points) return b.points - a.points;
return b.tiebreaker - a.tiebreaker;
});
standings.forEach((player, index) => {
const row = document.createElement('tr');
row.className = 'border-b border-gray-600 hover:bg-gray-700 transition-colors duration-200';
row.innerHTML = `
<td class="px-5 py-5 text-sm whitespace-nowrap">${index + 1}</td>
<td class="px-5 py-5 text-sm font-medium whitespace-nowrap">${player.name}</td>
<td class="px-5 py-5 text-sm whitespace-nowrap">${player.points}</td>
<td class="px-5 py-5 text-sm whitespace-nowrap">${player.tiebreaker.toFixed(2)}</td>
`;
tbody.appendChild(row);
});
standingsContainer.appendChild(table);
standingsContainer.classList.remove('hidden');
}
// --- Main Logic & Event Listeners ---
document.addEventListener('DOMContentLoaded', () => {
const firstInput = dynamicFieldsContainer.querySelector('.player-input');
if (firstInput) {
firstInput.focus();
}
updateDeleteButtonVisibility();
updateMakePairingsButton();
});
makePairingsBtn.addEventListener('click', () => {
const playerNames = getPlayers();
const roundsValue = parseInt(roundsSelect.value);
const mode = modeSelect.value;
let requiredPlayers;
if (mode === '1v1') {
requiredPlayers = 4;
} else if (mode === 'pod') {
requiredPlayers = 5;
}
if (playerNames.length < requiredPlayers) {
createModal('Invalid Player Count', `Please add at least ${requiredPlayers} players to start this type of tournament.`);
return;
}
setupContent.classList.add('hidden');
setupToggleIcon.classList.remove('rotate-180');
// Disable all setup fields
toggleSetupInputs(true);
if (currentRound === 0) {
standings = playerNames.map(name => ({
name,
points: 0,
tiebreaker: 0,
played: [],
byes: 0
}));
}
let newPairingPlayers;
if (mode === '1v1') {
newPairingPlayers = make1v1Pairings();
} else if (mode === 'pod') {
newPairingPlayers = makePodPairings();
}
if (newPairingPlayers.length === 0) {
createModal('Invalid Player Count', 'Cannot form valid pods with the current number of players. Please adjust the player count.');
return;
}
currentRound++;
if (mode === '1v1') {
pairings[currentRound] = newPairingPlayers.map(p => ({
players: p,
result: null,
winner: null,
type: '1v1'
}));
} else if (mode === 'pod') {
pairings[currentRound] = newPairingPlayers.map(p => ({
players: p,
result: null,
winners: [],
type: 'pod',
podId: podIdCounter++
}));
}
renderPairings(pairings[currentRound]);
renderStandings();
});
pairingsContainer.addEventListener('click', (e) => {
const mode = modeSelect.value;
const submitRoundBtn = document.getElementById('submit-round-btn');
let allMatchesComplete = true;
if (mode === '1v1') {
const winBtn = e.target.closest('.win-btn');
if (winBtn) {
const player = winBtn.dataset.player;
const opponent = winBtn.dataset.opponent;
const pairing = pairings[currentRound].find(p => p.players.includes(player) && p.players.includes(opponent));
if (!pairing) return;
const opponentBtn = e.target.parentElement.querySelector(`[data-player="${opponent}"]`);
winBtn.classList.toggle('selected-win');
if (winBtn.classList.contains('selected-win') && opponentBtn && opponentBtn.classList.contains('selected-win')) {
winBtn.classList.add('selected-draw');
opponentBtn.classList.add('selected-draw');
pairing.result = 'draw';
pairing.winner = null;
} else if (winBtn.classList.contains('selected-win')) {
if (opponentBtn) {
opponentBtn.classList.remove('selected-win', 'selected-draw');
}
winBtn.classList.remove('selected-draw');
pairing.result = 'win';
pairing.winner = player;
} else {
if (opponentBtn) {
opponentBtn.classList.remove('selected-draw');
}
pairing.result = null;
pairing.winner = null;
}
const centerText = winBtn.closest('.pairing-item').querySelector('.text-gray-400');
if (pairing.result === 'draw') {
centerText.textContent = 'Draw';
} else {
centerText.textContent = 'vs';
}
}
allMatchesComplete = pairings[currentRound].every(p => p.result !== null || p.players[1] === 'Bye');
} else if (mode === 'pod') {
const podBtn = e.target.closest('.pod-btn');
if (podBtn) {
const podContainer = podBtn.closest('.flex-wrap');
const player = podBtn.dataset.player;
const podId = podContainer.dataset.podId;
const pairing = pairings[currentRound].find(p => p.podId == podId);
if (!pairing) return;
// Toggle selection
podBtn.classList.toggle('selected-win');
podBtn.classList.remove('selected-draw');
const selectedButtons = Array.from(podContainer.querySelectorAll('.pod-btn.selected-win'));
const allButtons = Array.from(podContainer.querySelectorAll('.pod-btn'));
if (selectedButtons.length === 0) {
pairing.result = null;
pairing.winners = [];
} else if (selectedButtons.length === 1) {
allButtons.forEach(btn => btn.classList.remove('selected-draw'));
pairing.result = 'win';
pairing.winner = selectedButtons[0].dataset.player;
pairing.winners = [selectedButtons[0].dataset.player];
} else {
allButtons.forEach(btn => btn.classList.remove('selected-win'));
selectedButtons.forEach(btn => btn.classList.add('selected-draw'));
pairing.result = 'draw';
pairing.winners = selectedButtons.map(btn => btn.dataset.player);
}
}
allMatchesComplete = pairings[currentRound].every(p => p.result !== null);
}
if (submitRoundBtn) {
submitRoundBtn.disabled = !allMatchesComplete;
submitRoundBtn.classList.toggle('opacity-50', !allMatchesComplete);
submitRoundBtn.classList.toggle('cursor-not-allowed', !allMatchesComplete);
submitRoundBtn.classList.toggle('hover:bg-orange-600', allMatchesComplete);
}
});
document.addEventListener('click', (e) => {
const submitRoundBtn = e.target.closest('#submit-round-btn');
if (submitRoundBtn) {
const roundsValue = parseInt(roundsSelect.value);
updateStandings();
if (currentRound >= roundsValue) {
// Tournament is complete
pairingsContainer.classList.add('hidden');
const standingsTitle = document.getElementById('standings-title');
if (standingsTitle) {
standingsTitle.textContent = 'Standings - Final';
}
createModal('Tournament Complete', 'The tournament has reached its conclusion! The final standings are now displayed below.');
return;
}
const mode = modeSelect.value;
let newPairingPlayers;
if (mode === '1v1') {
newPairingPlayers = make1v1Pairings();
} else if (mode === 'pod') {
newPairingPlayers = makePodPairings();
}
currentRound++;
if (mode === '1v1') {
pairings[currentRound] = newPairingPlayers.map(p => ({
players: p,
result: null,
winner: null,
type: '1v1'
}));
} else if (mode === 'pod') {
pairings[currentRound] = newPairingPlayers.map(p => ({
players: p,
result: null,
winners: [],
type: 'pod',
podId: podIdCounter++
}));
}
renderPairings(pairings[currentRound]);
}
});
resetBtn.addEventListener('click', () => {
createModal('Confirm Restart', 'Are you sure you want to restart the event? All pairings and standings will be lost.', 'confirm', (confirmed) => {
if (confirmed) {
pairings = {};
standings = [];
currentRound = 0;
pairingsContainer.innerHTML = '';
standingsContainer.innerHTML = '';
toggleSetupInputs(false); // Re-enable setup fields
updateDeleteButtonVisibility();
updateMakePairingsButton();
setupContent.classList.remove('hidden');
setupToggleIcon.classList.add('rotate-180');
}
});
});
downloadBtn.addEventListener('click', () => {
const playerNames = getPlayers();
const tournamentData = {
title: titleInput.value,
date: dateInput.value,
mode: modeSelect.value,
rounds: roundsSelect.value,
players: playerNames,
pairings,
standings,
currentRound
};
const jsonData = JSON.stringify(tournamentData, null, 2);
const blob = new Blob([jsonData], { type: 'text/plain;charset=utf-8' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'tournament_data.txt';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
try {
const loadedData = JSON.parse(event.target.result);
titleInput.value = loadedData.title;
dateInput.value = loadedData.date;
modeSelect.value = loadedData.mode;
roundsSelect.value = loadedData.rounds;
dynamicFieldsContainer.innerHTML = '';
loadedData.players.forEach(name => {
const newRow = createPlayerInputRow();
newRow.querySelector('.player-input').value = name;
dynamicFieldsContainer.appendChild(newRow);
});
pairings = loadedData.pairings;
standings = loadedData.standings;
currentRound = loadedData.currentRound;
if (currentRound > 0) {
const currentRoundPairings = pairings[currentRound];
renderPairings(currentRoundPairings);
renderStandings();
toggleSetupInputs(true); // Disable inputs after loading
} else {
pairingsContainer.innerHTML = '';
standingsContainer.innerHTML = '';
toggleSetupInputs(false); // Enable inputs if no rounds have been played
}
updateDeleteButtonVisibility();
updateMakePairingsButton();
} catch (error) {
createModal('Load Error', 'Error loading file. Please ensure it is a valid tournament file.');
console.error('File load error:', error);
}
};
reader.readAsText(file);
}
});
setupToggleHeader.addEventListener('click', () => {
setupContent.classList.toggle('hidden');
setupToggleIcon.classList.toggle('rotate-180');
});
dynamicFieldsContainer.addEventListener('keydown', function(event) {
if (event.key === 'Enter') {
event.preventDefault();
const input = event.target;
const playerName = input.value.trim();
if (!isValidName(playerName) || playerName === '') {
input.style.borderColor = '#ef4444';
return;
}
input.style.borderColor = '';
const playerRows = dynamicFieldsContainer.querySelectorAll('.player-row');
const isLastRow = input.closest('.player-row') === playerRows[playerRows.length - 1];
if (isLastRow) {
const newRow = createPlayerInputRow();
dynamicFieldsContainer.appendChild(newRow);
updateDeleteButtonVisibility();
newRow.querySelector('.player-input').focus();
}
}
});
dynamicFieldsContainer.addEventListener('click', (event) => {
const removeButton = event.target.closest('.remove-player-btn');
if (removeButton && !removeButton.disabled) {
const playerRow = removeButton.closest('.player-row');
if (playerRow) {
playerRow.remove();
updateDeleteButtonVisibility();
updateMakePairingsButton();
}
}
});
dynamicFieldsContainer.addEventListener('input', (event) => {
const input = event.target;
if (isValidName(input.value) || input.value === '') {
input.style.borderColor = '';
}
updateMakePairingsButton();
});
modeSelect.addEventListener('change', updateMakePairingsButton);
roundsSelect.addEventListener('change', updateMakePairingsButton);
})();