Files
lara-schach-live/js/ui.js

255 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Lara Kiesewetter Live Schachturnier
* UI rendering: player info, clocks, highlights, moves list, games list, PGN display
*/
/* global $, Chess */
function showLoading(show) {
document.getElementById('loading-overlay').style.display = show ? 'flex' : 'none';
}
function hideError() {
document.getElementById('error-overlay').style.display = 'none';
}
function updatePlayerInfo() {
if (!currentGame) return;
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
const laraPlayer = laraIsWhite ? currentGame.white : currentGame.black;
const laraElo = laraIsWhite ? currentGame.whiteElo : currentGame.blackElo;
const laraEmoji = laraIsWhite ? '⬜' : '⬛';
const oppPlayer = laraIsWhite ? currentGame.black : currentGame.white;
const oppElo = laraIsWhite ? currentGame.blackElo : currentGame.whiteElo;
const oppEmoji = laraIsWhite ? '⬛' : '⬜';
document.getElementById('black-name').textContent = oppPlayer;
document.getElementById('black-elo').textContent = oppElo ? `(ELO: ${oppElo})` : '';
document.querySelector('#player-black .player-avatar').textContent = oppEmoji;
document.getElementById('white-name').textContent = laraPlayer;
document.getElementById('white-elo').textContent = laraElo ? `(ELO: ${laraElo})` : '';
document.querySelector('#player-white .player-avatar').textContent = laraEmoji;
updateClocks(currentMoveIndex);
const roundInfo = `Runde ${currentGame.round} ${currentGame.event || 'Turnier'}`;
document.getElementById('round-info').textContent = roundInfo;
const mobileRound = document.getElementById('round-info-mobile');
if (mobileRound) mobileRound.textContent = roundInfo;
const resultEl = document.getElementById('result-info');
if (currentGame.isLive) {
resultEl.innerHTML = '<span style="color: #4ade80;">● Laufen</span>';
} else {
resultEl.textContent = `Ergebnis: ${currentGame.result}`;
}
}
function updateClocks(moveIndex) {
if (!currentGame) return;
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
let whiteClock, blackClock;
if (moveIndex < 0) {
whiteClock = currentGame.whiteClock;
blackClock = currentGame.blackClock;
} else {
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
if (moveIndex < nonResultMoves.length) {
whiteClock = nonResultMoves[moveIndex].whiteClock;
blackClock = nonResultMoves[moveIndex].blackClock;
}
}
const laraClock = laraIsWhite ? whiteClock : blackClock;
const oppClock = laraIsWhite ? blackClock : whiteClock;
document.getElementById('black-clock').textContent = oppClock || '--:--:--';
document.getElementById('white-clock').textContent = laraClock || '--:--:--';
}
function highlightActivePlayer() {
if (!chess || !currentGame) return;
const laraPanel = document.getElementById('player-white');
const oppPanel = document.getElementById('player-black');
laraPanel.classList.remove('active');
oppPanel.classList.remove('active');
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
const isLaraTurn = (chess.turn() === 'w' && laraIsWhite) || (chess.turn() === 'b' && !laraIsWhite);
if (isLaraTurn) {
laraPanel.classList.add('active');
} else {
oppPanel.classList.add('active');
}
}
function highlightLastMove() {
if (!board || !chess || !currentGame) return;
$('#board [data-square]').removeClass('last-move-highlight');
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
if (currentMoveIndex >= 0 && currentMoveIndex < nonResultMoves.length) {
const moves = chess.history({ verbose: true });
if (moves.length > 0) {
const lastMoveData = moves[moves.length - 1];
$(`#board [data-square="${lastMoveData.from}"]`).addClass('last-move-highlight');
$(`#board [data-square="${lastMoveData.to}"]`).addClass('last-move-highlight');
}
}
}
function generatePGN(game) {
if (!game) return '';
let pgn = '';
if (game.event) pgn += `[Event "${game.event}"]\n`;
if (game.site) pgn += `[Site "${game.site}"]\n`;
if (game.date) pgn += `[Date "${game.date}"]\n`;
if (game.round) pgn += `[Round "${game.round}"]\n`;
if (game.white) pgn += `[White "${game.white}"]\n`;
if (game.black) pgn += `[Black "${game.black}"]\n`;
if (game.result) pgn += `[Result "${game.result}"]\n`;
if (game.whiteElo) pgn += `[WhiteElo "${game.whiteElo}"]\n`;
if (game.blackElo) pgn += `[BlackElo "${game.blackElo}"]\n`;
if (game.termination) pgn += `[Termination "${game.termination}"]\n`;
pgn += '\n';
const nonResultMoves = game.moves.filter(m => !m.isResult);
for (let i = 0; i < nonResultMoves.length; i += 2) {
const moveNumber = Math.floor(i / 2) + 1;
pgn += `${moveNumber}. ${nonResultMoves[i].san}`;
if (i + 1 < nonResultMoves.length) {
pgn += ` ${nonResultMoves[i + 1].san} `;
}
}
const resultMove = game.moves.find(m => m.isResult);
if (resultMove) {
pgn += ` ${resultMove.san}`;
}
return pgn.trim();
}
function updatePGNDisplay() {
if (!currentGame) return;
const text = generatePGN(currentGame);
document.querySelectorAll('.pgn-text').forEach(el => el.textContent = text);
}
function updateMovesList() {
if (!currentGame) return;
const movesList = document.getElementById('moves-list');
movesList.innerHTML = '';
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
for (let i = 0; i < nonResultMoves.length; i += 2) {
const moveNumber = Math.floor(i / 2) + 1;
const numSpan = document.createElement('span');
numSpan.className = 'move-number';
numSpan.textContent = `${moveNumber}.`;
movesList.appendChild(numSpan);
if (laraIsWhite) {
const laraMove = document.createElement('span');
laraMove.className = 'move lara-move';
laraMove.textContent = nonResultMoves[i].san;
laraMove.dataset.index = i;
movesList.appendChild(laraMove);
if (i + 1 < nonResultMoves.length) {
const oppMove = document.createElement('span');
oppMove.className = 'move opp-move';
oppMove.textContent = nonResultMoves[i + 1].san;
oppMove.dataset.index = i + 1;
movesList.appendChild(oppMove);
}
} else {
const oppMove = document.createElement('span');
oppMove.className = 'move opp-move';
oppMove.textContent = nonResultMoves[i].san;
oppMove.dataset.index = i;
movesList.appendChild(oppMove);
if (i + 1 < nonResultMoves.length) {
const laraMove = document.createElement('span');
laraMove.className = 'move lara-move';
laraMove.textContent = nonResultMoves[i + 1].san;
laraMove.dataset.index = i + 1;
movesList.appendChild(laraMove);
}
}
}
if (currentMoveIndex >= 0) {
const curMove = movesList.querySelector(`[data-index="${currentMoveIndex}"]`);
if (curMove) curMove.classList.add('current');
}
}
function updateAllGamesList() {
const list = document.getElementById('all-games-list');
list.innerHTML = '';
const sorted = [...allLaraGames].sort((a, b) => {
return (parseInt(a.round) || 0) - (parseInt(b.round) || 0);
});
for (const game of sorted) {
const entry = document.createElement('div');
entry.className = 'game-entry';
if (currentGame && game === currentGame) entry.classList.add('active');
const laraIsWhite = game.white.toLowerCase().includes('kiesewetter');
const opponent = laraIsWhite ? game.black : game.white;
const color = laraIsWhite ? '⬜ Weiß' : '⬛ Schwarz';
let resultIcon = '';
if (game.isLive) {
resultIcon = '⏳';
} else if (game.result === '1/2-1/2') {
resultIcon = '🤝';
} else if ((laraIsWhite && game.result === '1-0') || (!laraIsWhite && game.result === '0-1')) {
resultIcon = '✅';
} else {
resultIcon = '❌';
}
entry.innerHTML = `
<div class="game-round">${resultIcon} Runde ${game.round}</div>
<div class="game-players">Lara ${color} vs ${opponent}</div>
<div class="game-result">${game.isLive ? '● Laufen' : game.result}</div>
`;
entry.addEventListener('click', () => {
userSelectedGame = true;
currentGame = game;
previousMoveCount = -1;
currentMoveIndex = Number.MAX_SAFE_INTEGER;
updateBoard();
updatePlayerInfo();
updateMovesList();
updateAllGamesList();
updatePGNDisplay();
});
list.appendChild(entry);
}
}