// Player Management Functions
function getSavedPlayers() {
return JSON.parse(localStorage.getItem('ohHellPlayers') || '[]');
}
function savePlayers(players) {
localStorage.setItem('ohHellPlayers', JSON.stringify(players));
}
function addPlayer() {
const input = document.getElementById('newPlayerName');
const name = input.value.trim();
if (!name) {
alert('Please enter a player name');
return;
}
const players = getSavedPlayers();
if (players.includes(name)) {
alert('This player already exists!');
return;
}
players.push(name);
savePlayers(players);
loadSavedPlayers();
input.value = '';
updatePlayerInputs();
}
function removePlayer(name) {
let players = getSavedPlayers();
players = players.filter(p => p !== name);
savePlayers(players);
loadSavedPlayers();
updatePlayerInputs();
}
function loadSavedPlayers() {
const container = document.getElementById('savedPlayersList');
const players = getSavedPlayers();
if (players.length === 0) {
container.innerHTML = '
No saved players yet. Add some to get started!
';
} else {
container.innerHTML = players.map(player => `
${escapeHtml(player)}
`).join('');
}
}
function exportPlayers() {
const players = getSavedPlayers();
const data = {
exportDate: new Date().toISOString(),
players: players
};
const jsonString = JSON.stringify(data, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `oh-hell-players-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
alert('Player list exported successfully!');
}
function importPlayers(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = JSON.parse(e.target.result);
const importedPlayers = data.players || data;
if (!Array.isArray(importedPlayers)) {
throw new Error('Invalid file format');
}
const currentPlayers = getSavedPlayers();
const newPlayers = importedPlayers.filter(p => !currentPlayers.includes(p));
if (newPlayers.length === 0) {
alert('All players from the file already exist!');
return;
}
const allPlayers = [...new Set([...currentPlayers, ...importedPlayers])];
savePlayers(allPlayers);
loadSavedPlayers();
updatePlayerInputs();
alert(`Imported ${newPlayers.length} new player(s)!`);
} catch (error) {
alert('Error importing file: ' + error.message);
}
};
reader.readAsText(file);
// Reset file input
event.target.value = '';
}
// Settings and Sync Functions
function saveSettings() {
const syncUrl = normalizeSyncUrl(document.getElementById('syncUrl').value.trim());
const historySourceUrl = normalizeHistorySourceUrl(document.getElementById('historySourceUrl').value.trim());
const autoSync = document.getElementById('autoSyncCheck').checked;
if (syncUrl && !syncUrl.startsWith('http')) {
alert('Please enter a valid URL starting with http:// or https://');
return;
}
if (historySourceUrl && !historySourceUrl.startsWith('http')) {
alert('Please enter a valid history source URL starting with http:// or https://');
return;
}
localStorage.setItem('ohHellPlayerSyncUrl', syncUrl);
localStorage.setItem(HISTORY_SOURCE_URL_STORAGE_KEY, historySourceUrl || DEFAULT_HISTORY_SOURCE_URL);
localStorage.setItem('ohHellAutoSync', autoSync);
alert('Settings saved!');
closeModal('settingsModal');
}
function clearSyncUrl() {
if (confirm('Clear the sync URL?')) {
localStorage.removeItem('ohHellPlayerSyncUrl');
localStorage.removeItem('ohHellAutoSync');
document.getElementById('syncUrl').value = DEFAULT_SYNC_URL;
alert('Sync URL reset to default!');
}
}
function clearHistorySourceUrl() {
if (confirm('Reset the history source URL to the default GitHub history folder?')) {
localStorage.removeItem(HISTORY_SOURCE_URL_STORAGE_KEY);
document.getElementById('historySourceUrl').value = DEFAULT_HISTORY_SOURCE_URL;
alert('History source URL reset to default!');
}
}
function testSyncUrl() {
const syncUrl = normalizeSyncUrl(document.getElementById('syncUrl').value.trim());
if (!syncUrl) {
alert('Please enter a URL first');
return;
}
document.getElementById('syncUrl').value = syncUrl;
syncPlayersFromUrl(syncUrl, true);
}
async function testHistorySourceUrl() {
const historySourceUrl = normalizeHistorySourceUrl(document.getElementById('historySourceUrl').value.trim());
if (!historySourceUrl) {
alert('Please enter a history source URL first');
return;
}
document.getElementById('historySourceUrl').value = historySourceUrl;
try {
const paths = await discoverHistoryJsonPaths(historySourceUrl);
if (paths.length === 0) {
alert('No JSON files were discovered from that history source.');
return;
}
alert(`Discovered ${paths.length} JSON file(s) from the history source.`);
} catch (error) {
alert('Error testing history source: ' + error.message);
}
}
function syncPlayersFromUrl(url, showAlert = false) {
const normalizedUrl = normalizeSyncUrl(url);
fetch(normalizedUrl)
.then(response => response.json())
.then(data => {
const importedPlayers = data.players || data;
if (!Array.isArray(importedPlayers)) {
throw new Error('Invalid file format - must be a JSON array or object with "players" array');
}
const currentPlayers = getSavedPlayers();
const newPlayers = importedPlayers.filter(p => !currentPlayers.includes(p));
if (newPlayers.length === 0) {
if (showAlert) alert('All players already synced!');
return;
}
const allPlayers = [...new Set([...currentPlayers, ...importedPlayers])];
savePlayers(allPlayers);
loadSavedPlayers();
updatePlayerInputs();
if (showAlert) alert(`Synced ${newPlayers.length} new player(s)!`);
})
.catch(error => {
if (showAlert) {
alert('Error syncing players: ' + error.message);
}
console.error('Sync error:', error);
});
}
function autoSyncPlayers() {
const autoSync = localStorage.getItem('ohHellAutoSync') !== 'false';
const syncUrl = normalizeSyncUrl(localStorage.getItem('ohHellPlayerSyncUrl') || DEFAULT_SYNC_URL);
if (autoSync && syncUrl) {
syncPlayersFromUrl(syncUrl, false);
}
}
function manualSync() {
const syncUrl = normalizeSyncUrl(localStorage.getItem('ohHellPlayerSyncUrl') || DEFAULT_SYNC_URL);
if (!syncUrl) {
alert('No sync URL configured. Go to Settings to add one.');
return;
}
syncPlayersFromUrl(syncUrl, true);
}
function changeNumPlayers(delta) {
const input = document.getElementById('numPlayers');
const next = Math.min(11, Math.max(3, parseInt(input.value) + delta));
input.value = next;
document.getElementById('numPlayersDisplay').textContent = next;
updatePlayerInputs();
}
function setNumPlayers(n) {
document.getElementById('numPlayers').value = n;
document.getElementById('numPlayersDisplay').textContent = n;
updatePlayerInputs();
}
function updatePlayerInputs() {
const num = parseInt(document.getElementById('numPlayers').value);
const container = document.getElementById('playerInputs');
const savedPlayers = getSavedPlayers();
container.innerHTML = '';
if (savedPlayers.length === 0) {
container.innerHTML = 'No saved players. Click "Manage Players" to add some!
';
return;
}
for (let i = 0; i < num; i++) {
const row = document.createElement('div');
row.className = 'input-group';
const options = savedPlayers.map(p =>
`${escapeHtml(p)}
`
).join('');
row.innerHTML = `
${options}
`;
container.appendChild(row);
}
}
function togglePlayerDropdown(index) {
const panel = document.getElementById(`player-select-panel-${index}`);
const isOpen = panel.classList.contains('open');
document.querySelectorAll('.player-select-panel.open').forEach(p => p.classList.remove('open'));
if (!isOpen) panel.classList.add('open');
}
function selectPlayerOption(index, name) {
document.querySelectorAll('.player-select-panel.open').forEach(p => p.classList.remove('open'));
document.getElementById(`player${index}`).value = name;
document.getElementById(`player-select-label-${index}`).textContent = name;
// Mark selected state in panel
const panel = document.getElementById(`player-select-panel-${index}`);
panel.querySelectorAll('.player-select-option').forEach(opt => {
opt.classList.toggle('selected', opt.textContent === name);
});
}