0% found this document useful (0 votes)
8 views14 pages

Code

The document outlines a web application for tracking professional cricket statistics, featuring sections for player rosters, match logging, head-to-head statistics, match history, and user settings. It includes a user-friendly interface with forms for adding players and logging matches, as well as options for comparing players and managing data. The design supports both light and dark modes, enhancing usability and accessibility.

Uploaded by

geminihulu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views14 pages

Code

The document outlines a web application for tracking professional cricket statistics, featuring sections for player rosters, match logging, head-to-head statistics, match history, and user settings. It includes a user-friendly interface with forms for adding players and logging matches, as well as options for comparing players and managing data. The design supports both light and dark modes, enhancing usability and accessibility.

Uploaded by

geminihulu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

<!

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Professional Cricket Stats Tracker</title>
<script src="[Link]
<style>
:root {
--primary-color: #1a73e8; --secondary-color: #5f6368; --bg-color:
#f1f3f4;
--text-color: #202124; --light-grey: #dadce0; --white: #ffffff;
--danger-color: #d93025; --success-color: #1e8e3e; --warning-color:
#ff9800;
}
body {
font-family: "Google Sans", -apple-system, BlinkMacSystemFont, "Segoe
UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: var(--bg-color); color: var(--text-color);
line-height: 1.6; margin: 0; transition: background-color 0.3s, color
0.3s;
}
.header { background-color: var(--white); padding: 0 2rem; box-shadow: 0
2px 4px rgba(0,0,0,0.1); position: sticky; top: 0; z-index: 100; transition:
background-color 0.3s; }
.container { max-width: 1300px; margin: 0 auto; padding: 2rem; }
.card { background-color: var(--white); border-radius: 8px; box-shadow: 0
1px 2px 0 rgba(60,64,67,.3), 0 2px 6px 2px rgba(60,64,67,.15); padding: 1.5rem
2rem; margin-bottom: 2rem; transition: background-color 0.3s; }
h1, h2, h3 { color: var(--secondary-color); border-bottom: 1px solid var(--
light-grey); padding-bottom: 10px; margin-top: 0; transition: color 0.3s, border-
color 0.3s; }
h1 { text-align: center; border-bottom: none; margin: 1rem 0 2rem 0; color:
#3c4043; }
h3 { margin-top: 2rem; }
table { width: 100%; border-collapse: collapse; margin-top: 1rem; table-
layout: auto; }
th, td { border: 1px solid var(--light-grey); padding: 12px; text-align:
center; vertical-align: middle; transition: border-color 0.3s; }
td:first-child { text-align: left; }
thead th { background-color: #e9ecef; color: var(--secondary-color); font-
weight: 600; transition: background-color 0.3s, color 0.3s; }
tbody tr:nth-child(even) { background-color: #f8f9fa; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit,
minmax(200px, 1fr)); gap: 1rem; }
input, select, button { width: 100%; padding: 12px; border-radius: 5px;
border: 1px solid #ced4da; box-sizing: border-box; font-size: 1rem; }
button { color: var(--white); background-color: var(--primary-color);
border: none; cursor: pointer; font-weight: 600; transition: background-color 0.2s,
box-shadow 0.2s; }
.tab-nav { display: flex; flex-wrap: nowrap; overflow-x: auto; border-
bottom: 1px solid var(--light-grey); margin: 0 auto; max-width: 1300px; }
.tab-button { background: none; border: none; color: var(--secondary-
color); padding: 1rem 1.5rem; font-size: 1.1rem; font-weight: 500; cursor: pointer;
border-bottom: 3px solid transparent; margin-bottom: -1px; white-space: nowrap; }
.[Link] { color: var(--primary-color); border-bottom-color:
var(--primary-color); font-weight: 600; }
.tab-pane { display: none; } .[Link] { display: block; }
.settings-actions { display: flex; flex-direction: column; gap: 1rem; max-
width: 400px; margin-top: 1.5rem;}
.stats-header { display: flex; align-items: center; gap: 1.5rem; flex-wrap:
wrap; }
.stats-header img, #playerListTable img { width: 80px; height: 80px;
border-radius: 50%; object-fit: cover; background-color: var(--light-grey); }
.player-bio { display: flex; flex-direction: column; }
.player-bio p { margin: 2px 0; font-size: 0.9rem; }
.stats-filter, .h2h-filters-container { margin: 1.5rem 0; display: flex;
flex-wrap: wrap; gap: 1.5rem; align-items: center; }
.stats-filter > div, .h2h-filters > div { display: flex; gap: 0.5rem;
align-items: center;}
.stats-filter label, .h2h-filters label { font-weight: bold; }
.stats-tables-grid { display: grid; grid-template-columns: repeat(auto-fit,
minmax(350px, 1fr)); gap: 1rem; }
/* Redesigned Performance Row */
.performance-row { border: 1px solid var(--light-grey); border-radius: 8px;
padding: 1rem; margin-top: 1rem; }
.performance-row-header { display: flex; align-items: center; gap: 1rem;
border-bottom: 1px solid var(--light-grey); padding-bottom: 1rem; margin-bottom:
1rem; }
.performance-row-header select { flex-grow: 1; }
.perf-stats-grid { display: grid; grid-template-columns: repeat(auto-fit,
minmax(250px, 1fr)); gap: 1.5rem; }
.perf-group h4 { margin: 0 0 0.5rem 0; font-size: 1rem; color: var(--
primary-color); border-bottom: none; }
.perf-group .input-pair { display: grid; grid-template-columns: 80px 1fr;
gap: 0.5rem; align-items: center; margin-bottom: 0.5rem;}
.perf-group .input-pair label { font-size: 0.85rem; text-align: right; }
.dnb-group { display: flex; align-items: center; justify-content: center;
gap: 0.5rem; }
.dnb-group label { font-size: 0.8rem; }

/* Dark Mode */
[Link]-mode { --bg-color: #202124; --text-color: #e8eaed; --secondary-
color: #bdc1c6; --light-grey: #3c4043; --white: #28292d; }
[Link]-mode thead th { background-color: #3c4043; }
[Link]-mode tbody tr:nth-child(even) { background-color: #2a2a2a; }
[Link]-mode input, [Link]-mode select { background-color: #3c4043;
border-color: #5f6368; color: var(--text-color); }
</style>
</head>
<body>
<header class="header">
<nav class="tab-nav">
<button class="tab-button active" data-tab="home">Home</button>
<button class="tab-button" data-tab="log-match">Log Match</button>
<button class="tab-button" data-tab="h2h-stats">H2H Stats</button>
<button class="tab-button" data-tab="match-history">Match
History</button>
<button class="tab-button" data-tab="settings">Settings</button>
</nav>
</header>

<main class="container">
<div id="home" class="tab-pane active"><div class="card"><h2>Player
Roster</h2><form id="addPlayerForm" class="form-grid"><input type="text"
id="playerName" placeholder="Player Name" required><input type="date"
id="playerDob" title="Date of Birth"><input type="text" id="playerRole"
placeholder="Playing Role"><input type="text" id="battingStyle"
placeholder="Batting Style"><input type="text" id="bowlingStyle"
placeholder="Bowling Style"><input type="url" id="playerAvatar" placeholder="Avatar
Image URL"></form><button type="submit" form="addPlayerForm" class="btn-success"
style="margin-top: 1rem;">Add Player</button><table
id="playerListTable"><thead><tr><th>Avatar</th><th>Name</th><th>Role</
th><th>Actions</th></tr></thead><tbody></tbody></table></div></div>

<div id="log-match" class="tab-pane"><div class="card"><h2>Log a New


Match</h2><form id="logMatchForm"><div class="form-grid"><input type="date"
id="matchDate" required><input type="text" id="matchOpponent" placeholder="Opponent
Name"><select id="matchFormat" required><option value="">-- Select Format
--</option><option value="Test">Test</option><option
value="ODI">ODI</option><option value="T20">T20</option><option value="10 Overs">10
Overs</option><option value="5 Overs">5 Overs</option><option
value="Other">Other</option></select><select id="manOfTheMatch"><option value="">--
Man of the Match --</option></select></div><h3 style="margin-top:2rem">Player
Performances</h3><div id="performanceEntries"></div><button type="button"
id="addPerformanceBtn" style="margin-top:1rem">Add Player
Performance</button><button type="submit" class="btn-success" style="margin-
top:1rem;float:right">Save Match</button></form></div></div>

<div id="h2h-stats" class="tab-pane"><div class="card"><h3>Select Players


and Filters for Comparison</h3><div class="h2h-filters-container"><div class="h2h-
filters"><div><label>Player A:</label><select
id="h2hPlayerA"></select></div><div><label>Player B:</label><select
id="h2hPlayerB"></select></div></div><div class="h2h-
filters"><div><label>Format:</label><select
id="h2hFormatFilter"></select></div><div><label>Year:</label><select
id="h2hYearFilter"></select></div></div></div><button id="compareBtn"
style="margin-top:1rem; max-width: 200px;">Compare Careers</button><div
id="h2hResults" style="margin-top: 2rem;"></div></div></div>

<div id="match-history" class="tab-pane"><div class="card"><h2>Match


History</h2><table
id="matchHistoryTable"><thead><tr><th>Date</th><th>Format</th><th>Opponent</
th><th>Players</th><th>MOTM</th><th>Actions</th></tr></thead><tbody></tbody></
table></div></div>

<div id="settings" class="tab-pane"><div


class="card"><h2>Settings</h2><h3>Data Management</h3><div class="settings-
actions"><button id="exportDataBtn" class="btn-warning">Export Data</button><button
id="importDataBtn" class="btn-warning">Import Data</button><input type="file"
id="importFile" accept=".json" style="display:none"></div><h3 style="margin-top:
2rem;">Appearance</h3><div class="settings-actions"><button
id="darkModeToggle">Toggle Dark Mode</button></div><h3 style="margin-top:
2rem;">Archive (Trash)</h3><p>Items here are deleted permanently after 3
days.</p><table id="archiveTable"><thead><tr><th>Item</th><th>Type</th><th>Deleted
On</th><th>Actions</th></tr></thead><tbody></tbody></table></div></div>

<div id="career-stats" class="tab-pane">


<div class="card">
<div class="stats-header">
<img id="statsAvatar"
src="[Link]
g" alt="Player Avatar">
<div>
<h2 id="statsPlayerName" style="border-bottom:none; margin:
0;"></h2>
<div class="player-bio">
<p id="statsPlayerAge"></p><p id="statsPlayerRole"></p>
<p id="statsPlayerBatting"></p><p
id="statsPlayerBowling"></p>
</div>
</div>
</div>
<div class="stats-filter">
<div><label for="formatFilter">Format:</label><select
id="formatFilter"></select></div>
<div><label for="yearFilter">Year:</label><select
id="yearFilter"></select></div>
</div>
<h3>Batting</h3>

<table><thead><tr><th>M</th><th>I</th><th>NO</th><th>Runs</th><th>HS</th><th>Avg</
th><th>BF</th><th>SR</th></tr></thead>
<tbody><tr><td id="c_m_bat">-</td><td id="c_i_bat">-</td><td
id="c_no">-</td><td id="c_runs">-</td><td id="c_hs">-</td><td
id="c_avg_bat">-</td><td id="c_bf">-</td><td
id="c_sr_bat">-</td></tr></tbody></table>
<div class="stats-tables-grid">
<div><h3>Milestones &
Awards</h3><table><thead><tr><th>100s</th><th>50s</th><th>5W</th><th>MOTM</th></
tr></thead><tbody><tr><td id="c_100s">-</td><td id="c_50s">-</td><td
id="c_5w">-</td><td id="c_motm">-</td></tr></tbody></table></div>

<div><h3>Fielding</h3><table><thead><tr><th>Catches</th><th>Stumpings</th><th>Run
Outs</th></tr></thead><tbody><tr><td id="c_ct">-</td><td id="c_st">-</td><td
id="c_ro">-</td></tr></tbody></table></div>
</div>
<h3>Bowling</h3>

<table><thead><tr><th>M</th><th>I</th><th>Overs</th><th>Balls</th><th>Runs</
th><th>Wkts</th><th>BBI</th><th>Avg</th><th>Econ</th><th>SR</th></tr></thead>
<tbody><tr><td id="c_m_bowl">-</td><td id="c_i_bowl">-</td><td
id="c_overs">-</td><td id="c_balls_bowl">-</td><td id="c_runs_con">-</td><td
id="c_wkts">-</td><td id="c_bbi">-</td><td id="c_avg_bowl">-</td><td id="c_econ">-
</td><td id="c_sr_bowl">-</td></tr></tbody></table>
<h3 style="margin-top: 2rem;">Runs per Innings Chart</h3>
<canvas id="runsChart"></canvas>
</div>
</div>
</main>

<script>
[Link]('DOMContentLoaded', () => {
// --- DOM Elements ---
const tabNav = [Link]('.tab-nav');
const tabPanes = [Link]('.tab-pane');
const addPlayerForm = [Link]('addPlayerForm');
const playerListTableBody = [Link]('#playerListTable tbody');
const logMatchForm = [Link]('logMatchForm');
const addPerformanceBtn = [Link]('addPerformanceBtn');
const performanceEntries = [Link]('performanceEntries');
const manOfTheMatchSelect = [Link]('manOfTheMatch');
const formatFilterSelect = [Link]('formatFilter');
const yearFilterSelect = [Link]('yearFilter');
const matchHistoryTableBody = [Link]('#matchHistoryTable
tbody');
const archiveTableBody = [Link]('#archiveTable tbody');
const exportDataBtn = [Link]('exportDataBtn');
const importDataBtn = [Link]('importDataBtn');
const importFile = [Link]('importFile');
const darkModeToggle = [Link]('darkModeToggle');
const h2hPlayerASelect = [Link]('h2hPlayerA');
const h2hPlayerBSelect = [Link]('h2hPlayerB');
const h2hFormatFilter = [Link]('h2hFormatFilter');
const h2hYearFilter = [Link]('h2hYearFilter');
const compareBtn = [Link]('compareBtn');
const h2hResultsDiv = [Link]('h2hResults');
const runsChartCanvas = [Link]('runsChart');
let runsChart;

// --- App State ---


let db = { players: [], matches: [], trash: [] };
let currentStatsPlayerId = null;

// --- INITIALIZATION ---


loadData();
if ([Link]('darkMode') === 'enabled')
[Link]('dark-mode');

// --- EVENT LISTENERS ---


[Link]('click', handleTabSwitch);
[Link]('submit', handleAddPlayer);
[Link]('click', handlePlayerListClick);
[Link]('click', addPerformanceRow);
[Link]('submit', handleLogMatch);
[Link]('change', handleFilterChange);
[Link]('change', handleFilterChange);
[Link]('click', handleMatchHistoryClick);
[Link]('click', handleArchiveClick);
[Link]('click', exportData);
[Link]('click', () => [Link]());
[Link]('change', importData);
[Link]('click', toggleDarkMode);
[Link]('click', displayH2HStats);

// --- TAB SWITCHING ---


function switchTab(targetTabId) {
if (targetTabId === 'h2h-stats') populateH2HDropdowns();
if (targetTabId === 'log-match') {
populateMOTMSelect();
if ([Link]('.performance-row').length ===
0) addPerformanceRow();
}
[Link](pane => [Link]('active'));
[Link](targetTabId)?.[Link]('active');

[Link]('.tab-button').forEach(btn =>
[Link]('active'));
const targetButton = [Link](`[data-tab='${targetTabId}']`);
if (targetButton) [Link]('active');
}
function handleTabSwitch(e) {
const tabButton = [Link]('.tab-button');
if (!tabButton) return;
switchTab([Link]);
}

// --- DARK MODE ---


function toggleDarkMode() {
[Link]('dark-mode');
[Link]('darkMode', [Link]('dark-
mode') ? 'enabled' : 'disabled');
}

// --- DATA HANDLING ---


function saveData() { [Link]('cricketAppDb', [Link](db));
}
function loadData() {
const storedDb = [Link]('cricketAppDb');
if (storedDb) db = [Link](storedDb);
if (![Link]) [Link] = [];
purgeOldTrash();
renderAll();
}
function renderAll() {
renderPlayerList();
renderMatchHistory();
renderArchive();
updateAllPlayerDropdowns();
}
function exportData() {
if ([Link] === 0 && [Link] === 0) return alert("No
data to export.");
const dataStr = [Link](db, null, 2);
const dataBlob = new Blob([dataStr], {type: "application/json"});
const url = [Link](dataBlob);
const link = [Link]('a');
[Link] = url;
[Link] = `cricket_stats_backup_${new
Date().toISOString().slice(0,10)}.json`;
[Link]();
[Link](url);
}
function importData(event) {
const file = [Link][0]; if (!file) return;
const reader = new FileReader();
[Link] = function(e) {
try {
const importedDb = [Link]([Link]);
if (importedDb && [Link]([Link]) &&
[Link]([Link])) {
if (confirm("This will overwrite all current data. Are you
sure?")) {
db = importedDb;
if(![Link]) [Link] = [];
saveData();
renderAll();
switchTab('home');
alert("Data imported successfully!");
}
} else { alert("Invalid data file format."); }
} catch (error) { alert("Error reading file."); }
};
[Link](file);
[Link] = '';
}

// --- PLAYER MANAGEMENT ---


function handleAddPlayer(e) {
[Link]();
[Link]({
id: [Link](), name:
[Link]('playerName').[Link]() || 'Unnamed Player',
role: [Link]('playerRole').[Link](),
battingStyle: [Link]('battingStyle').[Link](),
bowlingStyle: [Link]('bowlingStyle').[Link](),
avatarUrl: [Link]('playerAvatar').[Link](),
dob: [Link]('#playerDob').value
});
saveData();
renderPlayerList();
[Link]();
updateAllPlayerDropdowns();
}
function renderPlayerList() {
[Link] = '';
const defaultAvatar =
'[Link]
[Link](player => {
const row = [Link]('tr');
[Link] = `<td><img src="${[Link] || defaultAvatar}"
alt="Avatar"></td>
<td>${[Link]}</td><td>${[Link] || '-'}</td>
<td><button class="btn-small" data-player-id="${[Link]}" data-
action="view-stats">View Stats</button>
<button class="btn-small btn-danger" data-player-id="$
{[Link]}" data-action="delete-player">Delete</button></td>`;
[Link](row);
});
}
function handlePlayerListClick(e) {
const targetButton = [Link]('button');
if (!targetButton) return;
const { action, playerId } = [Link];
if (action === 'view-stats') openStatsPage(parseInt(playerId));
else if (action === 'delete-player') if (confirm('Are you sure? This will
move the player to the Archive.')) deleteToArchive('player', parseInt(playerId));
}
function updateAllPlayerDropdowns() {
populateH2HDropdowns();
populateMOTMSelect();
}

// --- MATCH LOGGING & HISTORY ---


function populateMOTMSelect() {
const currentSelection = [Link];
[Link] = '<option value="">-- Man of the Match
--</option>';
[Link](player => {
[Link] += `<option value="${[Link]}">$
{[Link]}</option>`;
});
[Link] = currentSelection;
}
function addPerformanceRow() {
if ([Link] === 0) {
if ([Link] === 0) alert('Add a player on
the "Home" tab first.');
return;
}
const row = [Link]('div');
[Link] = 'performance-row';
const playerOptions = [Link](p => `<option value="${[Link]}">$
{[Link]}</option>`).join('');
[Link] = `<div class="performance-row-header"><select data-
field="playerId">${playerOptions}</select></div>
<div class="perf-stats-grid">
<div class="perf-group"><h4>Batting</h4>
<div class="input-pair"><label>Did Not Bat:</label><input
type="checkbox" data-field="dnbBat"></div>
<div class="input-pair"><label>Runs:</label><input
type="number" min="0" placeholder="R" data-field="runs"></div>
<div class="input-pair"><label>Balls:</label><input
type="number" min="0" placeholder="B" data-field="balls"></div>
<div class="input-pair"><label>4s:</label><input type="number"
min="0" placeholder="4s" data-field="fours"></div>
<div class="input-pair"><label>6s:</label><input type="number"
min="0" placeholder="6s" data-field="sixes"></div>
<div class="input-pair"><label>Out?</label><select data-
field="out"><option value="yes">Yes</option><option
value="no">No</option></select></div>
</div>
<div class="perf-group"><h4>Bowling</h4>
<div class="input-pair"><label>Did Not Bowl:</label><input
type="checkbox" data-field="dnbBowl"></div>
<div class="input-pair"><label>Overs:</label><input type="text"
placeholder="e.g. 4.0" data-field="overs"></div>
<div class="input-pair"><label>Runs Con:</label><input
type="number" min="0" placeholder="R" data-field="runsCon"></div>
<div class="input-pair"><label>Wickets:</label><input
type="number" min="0" placeholder="W" data-field="wkts"></div>
</div>
<div class="perf-group"><h4>Fielding</h4>
<div class="input-pair"><label>Catches:</label><input
type="number" min="0" placeholder="Ct" data-field="catches"></div>
<div class="input-pair"><label>Stumpings:</label><input
type="number" min="0" placeholder="St" data-field="stumpings"></div>
<div class="input-pair"><label>Run Outs:</label><input
type="number" min="0" placeholder="RO" data-field="runOuts"></div>
</div>
</div>`;
[Link](row);
}
function handleLogMatch(e) {
[Link]();
const performances = [];
[Link]('.performance-row').forEach(row => {
const performanceData = {};
[Link]('[data-field]').forEach(input => {
const field = [Link];
if ([Link] === 'checkbox') performanceData[field] =
[Link];
else if ([Link] === 'number' || [Link] ===
'playerId') performanceData[field] = parseInt([Link]) || 0;
else performanceData[field] = [Link];
});
[Link](performanceData);
});
if ([Link] === 0) return alert('A match needs at least one
performance.');
[Link]({
id: [Link](), date: [Link]('matchDate').value,
format: [Link]('matchFormat').value,
opponent: [Link]('matchOpponent').[Link](),
motmPlayerId: parseInt([Link]) || null,
performances: performances
});
saveData();
[Link]();
[Link] = '';
addPerformanceRow();
alert('Match logged successfully!');
renderMatchHistory();
}
function renderMatchHistory() {
[Link] = '';
[...[Link]].reverse().forEach(match => {
const playerNames = [Link](p => [Link](pl =>
[Link] === [Link])?.name || 'N/A').join(', ');
const motm = [Link](pl => [Link] === [Link])?.name
|| '-';
const row = [Link]('tr');
[Link] = `<td>${[Link]}</td><td>${[Link]}</td><td>$
{[Link] || '-'}</td><td>${playerNames}</td><td>${motm}</td>
<td><button class="btn-small btn-danger" data-match-id="$
{[Link]}" data-action="delete-match">Delete</button></td>`;
[Link](row);
});
}
function handleMatchHistoryClick(e) {
const targetButton = [Link]('button');
if (!targetButton) return;
if([Link] === 'delete-match') {
const matchId = parseInt([Link]);
if (confirm('Are you sure? This will move the match to the Archive.'))
deleteToArchive('match', matchId);
}
}

// --- H2H STATS ---


function populateH2HDropdowns() {
const createOptions = (select) => {
const currentVal = [Link];
[Link] = `<option value="">-- Select Player --</option>`;
[Link](p => { [Link] += `<option value="$
{[Link]}">${[Link]}</option>`; });
[Link] = currentVal;
};
populateOptions(h2hFormatFilter, new Set([Link](m => [Link])),
'All Formats');
populateOptions(h2hYearFilter, new Set([Link](m => [Link] ? new
Date([Link]).getFullYear() : null)), 'All Years', true);
createOptions(h2hPlayerASelect);
createOptions(h2hPlayerBSelect);
}
function displayH2HStats() {
const pA_id = parseInt([Link]);
const pB_id = parseInt([Link]);
if (!pA_id || !pB_id || pA_id === pB_id) return [Link] =
'<p>Please select two different players.</p>';

const filters = { format: [Link], year:


[Link] };
const statsA = getPlayerStats(pA_id, filters);
const statsB = getPlayerStats(pB_id, filters);
const playerA = [Link](p => [Link] === pA_id);
const playerB = [Link](p => [Link] === pB_id);

const generateRow = (label, valA, valB) => `<tr><td>${label}</td><td>$


{valA}</td><td>${valB}</td></tr>`;

[Link] = `<h3>Comparison: ${[Link]} vs $


{[Link]} (${[Link] || 'All Formats'}, ${[Link] || 'All
Years'})</h3>
<h4>Batting & Fielding</h4><table><thead><tr><th>Stat</th><th>$
{[Link]}</th><th>${[Link]}</th></tr></thead><tbody>
${generateRow('Matches',[Link],[Link])}
${generateRow('Innings',[Link],[Link])}
${generateRow('Not Outs',[Link],[Link])}
${generateRow('Runs',[Link],[Link])}
${generateRow('High Score',[Link],[Link])}
${generateRow('Average',[Link],[Link])}
${generateRow('Balls Faced',[Link],[Link])}
${generateRow('Strike Rate',[Link],[Link])}
${generateRow('100s / 50s', `${[Link]}/${[Link]}`, `$
{[Link]}/${[Link]}`)}
${generateRow('4s / 6s', `${[Link]}/${[Link]}`, `$
{[Link]}/${[Link]}`)}
${generateRow('Catches',[Link],[Link])}
${generateRow('Stumpings',[Link],[Link])}
${generateRow('Run Outs',[Link],[Link])}
${generateRow('MOTM Awards',[Link],[Link])}
</tbody></table>
<h4>Bowling</h4><table><thead><tr><th>Stat</th><th>${[Link]}</
th><th>${[Link]}</th></tr></thead><tbody>
${generateRow('Innings',[Link],[Link])}
${generateRow('Overs',[Link],[Link])}
${generateRow('Wickets',[Link],[Link])}
${generateRow('Best Bowling',[Link],[Link])}
${generateRow('Average',[Link],[Link])}
${generateRow('Economy',[Link],[Link])}
${generateRow('Strike Rate',[Link],[Link])}
${generateRow('5 Wicket
Hauls',[Link],[Link])}
</tbody></table>`;
}

// --- STATS DISPLAY & CALCULATION ---


function getPlayerStats(playerId, filters) {
let performances = [Link](match => [Link](p
=> [Link] === playerId).map(p => ({ ...p, date: [Link], format:
[Link], opponent: [Link], motmPlayerId: [Link] })));
if ([Link] && [Link] !== 'Overall') performances =
[Link](p => [Link] === [Link]);
if ([Link] && [Link] !== 'All') performances =
[Link](p => [Link] && new Date([Link]).getFullYear() == [Link]);

let stats = { matches: new Set([Link](p => [Link] +


[Link])).size, inningsBat: 0, notOuts: 0, runs: 0, highestScore: 0, ballsFaced:
0, hundreds: 0, fifties: 0, fours: 0, sixes: 0, inningsBowl: 0, ballsBowled: 0,
runsConceded: 0, wickets: 0, bestBBIWickets: 0, bestBBIRuns: Infinity,
fiveWicketHauls: 0, catches: 0, stumpings: 0, runOuts: 0, motm: 0 };
[Link](p => {
if (![Link]) { [Link]++; if ([Link] === 'no') [Link]+
+; }
if (![Link] && [Link]) [Link]++;
if([Link] === playerId) [Link]++;
[Link] += [Link] || 0; [Link] += [Link] || 0;
[Link] += [Link] || 0; [Link] += [Link] || 0;
if (([Link] || 0) > [Link]) [Link] = [Link] ||
0;
if (([Link] || 0) >= 100) [Link]++; else if (([Link] || 0) >=
50) [Link]++;
const [oversInt, partial] = ([Link] || '0.0').split('.').map(Number);
[Link] += (oversInt || 0) * 6 + (partial || 0);
[Link] += [Link] || 0; [Link] += [Link] || 0;
if (([Link] || 0) > [Link] || (([Link] || 0) ===
[Link] && ([Link] || 0) < [Link])) {
[Link] = [Link] || 0; [Link] = [Link]
|| 0;
}
if (([Link] || 0) >= 5) [Link]++;
[Link] += [Link] || 0; [Link] += [Link] || 0;
[Link] += [Link] || 0;
});
const timesOut = [Link] - [Link];
[Link] = timesOut > 0 ? ([Link] / timesOut).toFixed(2) : '∞';
[Link] = [Link] > 0 ? ([Link] / [Link] *
100).toFixed(2) : '0.00';
[Link] = [Link]([Link] / 6) + '.' + ([Link]
% 6);
[Link] = [Link] > 0 ? ([Link] /
[Link]).toFixed(2) : '–';
[Link] = [Link] > 0 ? ([Link] /
([Link] / 6)).toFixed(2) : '0.00';
[Link] = [Link] > 0 ? ([Link] /
[Link]).toFixed(2) : '–';
[Link] = [Link] === Infinity ? '-' : `$
{[Link]}/${[Link]}`;
return stats;
}
function openStatsPage(playerId) {
// This is the primary fix for the "View Stats" button.
// It now reliably activates the correct pane and deactivates others.
currentStatsPlayerId = playerId;
[Link](pane => [Link]('active'));
[Link]('.tab-button').forEach(btn =>
[Link]('active'));
[Link]('career-stats').[Link]('active');

const playerMatches = [Link](m => [Link](p =>


[Link] === playerId));
populateOptions(formatFilterSelect, new Set([Link](m =>
[Link])), 'Overall Career');
populateOptions(yearFilterSelect, new Set([Link](m => [Link] ?
new Date([Link]).getFullYear() : null)), 'All Years', true);
calculateAndDisplayStats(playerId, 'Overall', 'All');
}
function handleFilterChange() { if (currentStatsPlayerId)
calculateAndDisplayStats(currentStatsPlayerId, [Link],
[Link]); }
function calculateAndDisplayStats(playerId, formatFilter, yearFilter) {
const player = [Link](p => [Link] === playerId); if (!player)
return;
const stats = getPlayerStats(playerId, { format: formatFilter, year:
yearFilter });
const getAge = dobString => {
if (!dobString) return 'N/A';
const dob = new Date(dobString);
if (isNaN([Link]())) return 'N/A';
const ageDifMs = [Link]() - [Link]();
const ageDate = new Date(ageDifMs);
return `${[Link]([Link]() - 1970)} years old`;
};
[Link]('statsPlayerName').textContent = [Link];
[Link]('statsPlayerAge').textContent = `Age: $
{getAge([Link])}`;
[Link]('statsPlayerRole').textContent = `Role: $
{[Link] || 'N/A'}`;
[Link]('statsPlayerBatting').textContent = `Batting: $
{[Link] || 'N/A'}`;
[Link]('statsPlayerBowling').textContent = `Bowling: $
{[Link] || 'N/A'}`;
[Link]('statsAvatar').src = [Link] ||
'[Link]

const setStat = (id, val) => {


const el = [Link](id);
if (el) [Link] = val;
};
setStat('c_m_bat', [Link]); setStat('c_i_bat', [Link]);
setStat('c_no', [Link]);
setStat('c_runs', [Link]); setStat('c_hs', [Link]);
setStat('c_avg_bat', [Link]);
setStat('c_bf', [Link]); setStat('c_sr_bat', [Link]);
setStat('c_100s', [Link]); setStat('c_50s', [Link]);
setStat('c_5w', [Link]); setStat('c_motm', [Link]);
setStat('c_ct', [Link]); setStat('c_st', [Link]);
setStat('c_ro', [Link]);
setStat('c_m_bowl', [Link]); setStat('c_i_bowl', [Link]);
setStat('c_overs', [Link]);
setStat('c_balls_bowl', [Link]); setStat('c_runs_con',
[Link]);
setStat('c_wkts', [Link]); setStat('c_bbi', [Link]);
setStat('c_avg_bowl', [Link]);
setStat('c_econ', [Link]); setStat('c_sr_bowl', [Link]);
if (runsChart) [Link]();
const battingPerformances = [Link](m => [Link](p
=> [Link] === playerId && ![Link]));
runsChart = new Chart([Link]('2d'), {
type: 'line', data: {
labels: [Link]((p, i) => `Innings ${i+1}`),
datasets: [{ label: 'Runs per Innings', data:
[Link](p => [Link]), backgroundColor: 'rgba(26, 115, 232, 0.2)',
borderColor: 'rgba(26, 115, 232, 1)', borderWidth: 2, tension: 0.1 }]
}, options: { scales: { y: { beginAtZero: true } } }
});
}

// --- ARCHIVE ---


function purgeOldTrash() {
const threeDaysAgo = [Link]() - 3 * 24 * 60 * 60 * 1000;
if ([Link] > 0) {
[Link] = [Link](item => new Date([Link]).getTime() >
threeDaysAgo);
saveData();
}
}
function renderArchive() {
[Link] = '';
[...[Link]].reverse().forEach(item => {
const row = [Link]('tr');
const itemName = [Link] === 'player' ? [Link] : `Match on $
{[Link]}`;
[Link] = `<td>${itemName}</td><td>${[Link]}</td><td>${new
Date([Link]).toLocaleString()}</td>
<td><button class="btn-small btn-success" data-item-id="$
{[Link]}" data-item-type="${[Link]}"
data-action="restore">Restore</button>
<button class="btn-small btn-danger" data-item-id="${[Link]}"
data-item-type="${[Link]}" data-action="delete-perm">Delete
Permanently</button></td>`;
[Link](row);
});
}
function deleteToArchive(type, id) {
let itemIndex = -1, itemToMove = null;
if (type === 'player') {
itemIndex = [Link](p => [Link] === id);
if (itemIndex > -1) [itemToMove] = [Link](itemIndex, 1);
} else if (type === 'match') {
itemIndex = [Link](m => [Link] === id);
if (itemIndex > -1) [itemToMove] = [Link](itemIndex, 1);
}
if(itemToMove) {
[Link]({ type: type, data: itemToMove, deletedOn: new
Date().toISOString() });
saveData();
renderAll();
}
}
function handleArchiveClick(e) {
const targetButton = [Link]('button');
if (!targetButton) return;
const { action, itemId, itemType } = [Link];
const id = parseInt(itemId);
const itemIndex = [Link](i => [Link] === id && [Link] ===
itemType);
if (itemIndex === -1) return;
if (action === 'restore') {
const [item] = [Link](itemIndex, 1);
delete [Link];
if ([Link] === 'player') [Link]([Link]);
else if ([Link] === 'match') [Link]([Link]);
saveData();
renderAll();
// This is the fix for the stats update bug.
if (currentStatsPlayerId) {
calculateAndDisplayStats(currentStatsPlayerId,
[Link], [Link]);
}
} else if (action === 'delete-perm') {
if (confirm('This cannot be undone. Are you sure?')) {
[Link](itemIndex, 1);
saveData();
renderAll();
}
}
}

// --- UTILITY ---


function populateOptions(selectElement, itemSet, defaultOptionText, sortDesc =
false) {
const currentVal = [Link];
const defaultAllValue = [Link]('All') ? 'All' : '';
[Link] = `<option value="${defaultAllValue}">$
{defaultOptionText}</option>`;
let items = [...itemSet].filter(Boolean);
if (sortDesc) [Link]((a,b) => b-a); else [Link]();
[Link](item => { [Link] += `<option value="$
{item}">${item}</option>`; });
[Link] = currentVal;
}
});
</script>

</body>
</html>

You might also like