152 lines
5.2 KiB
JavaScript
152 lines
5.2 KiB
JavaScript
// Toggle leaderboard visibility
|
|
const toggleBtn = document.getElementById('toggleLeaderboard');
|
|
const leaderboardSection = document.getElementById('leaderboardSection');
|
|
const contentContainer = document.getElementById('contentContainer');
|
|
|
|
toggleBtn.addEventListener('click', () => {
|
|
if (leaderboardSection.style.display === 'none') {
|
|
leaderboardSection.style.display = '';
|
|
toggleBtn.textContent = 'Hide';
|
|
contentContainer.classList.remove('single-column');
|
|
} else {
|
|
leaderboardSection.style.display = 'none';
|
|
toggleBtn.textContent = 'Show';
|
|
contentContainer.classList.add('single-column');
|
|
}
|
|
});
|
|
|
|
// Problem search functionality
|
|
const problemSearch = document.getElementById('problemSearch');
|
|
const problemsContainer = document.getElementById('problemsContainer');
|
|
const problemItems = problemsContainer.querySelectorAll('.problem-item');
|
|
|
|
problemSearch.addEventListener('input', () => {
|
|
const searchTerm = problemSearch.value.toLowerCase();
|
|
problemItems.forEach(item => {
|
|
const name = item.dataset.name.toLowerCase();
|
|
const desc = item.dataset.desc?.toLowerCase() || '';
|
|
if (name.includes(searchTerm) || desc.includes(searchTerm)) {
|
|
item.style.display = '';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
|
|
// Leaderboard filtering and sorting
|
|
const userSearch = document.getElementById('userSearch');
|
|
const problemFilter = document.getElementById('problemFilter');
|
|
const runtimeFilter = document.getElementById('runtimeFilter');
|
|
const leaderboardBody = document.getElementById('leaderboardBody');
|
|
const leaderboardRows = Array.from(leaderboardBody.querySelectorAll('tr'));
|
|
const sortableHeaders = document.querySelectorAll('.sortable');
|
|
|
|
// Current sort state
|
|
let currentSort = {
|
|
column: null,
|
|
direction: 'asc'
|
|
};
|
|
|
|
// Filter leaderboard
|
|
function filterLeaderboard() {
|
|
const userTerm = userSearch.value.toLowerCase();
|
|
const problemTerm = problemFilter.value.toLowerCase();
|
|
const runtimeType = runtimeFilter.value;
|
|
|
|
leaderboardRows.forEach(row => {
|
|
const user = row.dataset.user.toLowerCase();
|
|
const problem = row.dataset.problem.toLowerCase();
|
|
const runtime = parseFloat(row.dataset.runtime);
|
|
const showUser = user.includes(userTerm);
|
|
const showProblem = problem.includes(problemTerm);
|
|
|
|
let showRuntime = true;
|
|
if (runtimeType === 'best') {
|
|
// Find if this is the best runtime for this user+problem combo
|
|
const userProblemRows = leaderboardRows.filter(r =>
|
|
r.dataset.user === row.dataset.user &&
|
|
r.dataset.problem === row.dataset.problem
|
|
);
|
|
const bestRuntime = Math.min(...userProblemRows.map(r => parseFloat(r.dataset.runtime)));
|
|
showRuntime = runtime === bestRuntime;
|
|
} else if (runtimeType === 'worst') {
|
|
// Find if this is the worst runtime for this user+problem combo
|
|
const userProblemRows = leaderboardRows.filter(r =>
|
|
r.dataset.user === row.dataset.user &&
|
|
r.dataset.problem === row.dataset.problem
|
|
);
|
|
const worstRuntime = Math.max(...userProblemRows.map(r => parseFloat(r.dataset.runtime)));
|
|
showRuntime = runtime === worstRuntime;
|
|
}
|
|
|
|
if (showUser && showProblem && showRuntime) {
|
|
row.style.display = '';
|
|
} else {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Sort leaderboard
|
|
function sortLeaderboard(column, direction) {
|
|
const rows = Array.from(leaderboardBody.querySelectorAll('tr'));
|
|
const index = Array.from(document.querySelectorAll('th')).findIndex(th => th.dataset.sort === column);
|
|
|
|
rows.sort((a, b) => {
|
|
let aValue = a.cells[index].textContent;
|
|
let bValue = b.cells[index].textContent;
|
|
|
|
// Special handling for numeric columns
|
|
if (column === 'runtime' || column === 'memory' || column === 'rank') {
|
|
aValue = parseFloat(aValue) || 0;
|
|
bValue = parseFloat(bValue) || 0;
|
|
return direction === 'asc' ? aValue - bValue : bValue - aValue;
|
|
}
|
|
|
|
// Special handling for timestamps
|
|
if (column === 'timestamp') {
|
|
aValue = new Date(aValue).getTime();
|
|
bValue = new Date(bValue).getTime();
|
|
return direction === 'asc' ? aValue - bValue : bValue - aValue;
|
|
}
|
|
|
|
// Default string comparison
|
|
aValue = aValue.toLowerCase();
|
|
bValue = bValue.toLowerCase();
|
|
if (aValue < bValue) return direction === 'asc' ? -1 : 1;
|
|
if (aValue > bValue) return direction === 'asc' ? 1 : -1;
|
|
return 0;
|
|
});
|
|
|
|
// Re-append rows in sorted order
|
|
rows.forEach(row => leaderboardBody.appendChild(row));
|
|
}
|
|
|
|
// Set up event listeners
|
|
userSearch.addEventListener('input', filterLeaderboard);
|
|
problemFilter.addEventListener('input', filterLeaderboard);
|
|
runtimeFilter.addEventListener('change', filterLeaderboard);
|
|
|
|
// Set up sorting
|
|
sortableHeaders.forEach(header => {
|
|
header.addEventListener('click', () => {
|
|
const column = header.dataset.sort;
|
|
|
|
// Reset all sort indicators
|
|
sortableHeaders.forEach(h => {
|
|
h.classList.remove('sort-asc', 'sort-desc');
|
|
});
|
|
|
|
// Determine new sort direction
|
|
if (currentSort.column === column) {
|
|
currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
currentSort.column = column;
|
|
currentSort.direction = 'asc';
|
|
}
|
|
|
|
// Apply new sort
|
|
header.classList.add(`sort-${currentSort.direction}`);
|
|
sortLeaderboard(column, currentSort.direction);
|
|
});
|
|
}); |