103 lines
3.4 KiB
JavaScript
103 lines
3.4 KiB
JavaScript
document.addEventListener("DOMContentLoaded", () => {
|
|
loadLeaderboard();
|
|
});
|
|
|
|
function loadLeaderboard() {
|
|
fetch('Leaderboard.php')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === "success") {
|
|
// Render Top 10
|
|
renderLeaderboard(data.leaderboard);
|
|
|
|
// Render Ranking Saya (User Rank)
|
|
if (data.user_rank) {
|
|
renderUserRank(data.user_rank);
|
|
}
|
|
}
|
|
})
|
|
.catch(error => console.error("Error loading leaderboard:", error));
|
|
}
|
|
|
|
// ... fungsi renderLeaderboard tetap sama ...
|
|
|
|
// TAMBAHKAN FUNGSI INI DI BAWAH
|
|
function renderUserRank(user) {
|
|
const container = document.getElementById('userRankContainer');
|
|
if (!container) return;
|
|
|
|
// Format angka skor
|
|
const formattedScore = new Intl.NumberFormat().format(user.score);
|
|
|
|
// HTML structure sesuai CSS .your-rank-container
|
|
const html = `
|
|
<div class="your-rank-container">
|
|
<div style="color: #00ff88; margin-bottom: 10px; font-weight: bold; text-transform: uppercase; letter-spacing: 2px;">
|
|
</div>
|
|
<div class="your-rank-item">
|
|
<div class="rank-badge" style="background: #00ff88; color: #000; box-shadow: 0 0 15px #00ff88;">
|
|
${user.rank}
|
|
</div>
|
|
<div class="player-info">
|
|
<div class="player-name">${escapeHtml(user.username)}</div>
|
|
</div>
|
|
<div class="player-score">
|
|
<div class="score-value">${formattedScore}</div>
|
|
<div class="score-label">Points</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
// ... fungsi escapeHtml tetap sama ...
|
|
|
|
function renderLeaderboard(players) {
|
|
const listContainer = document.getElementById('leaderboardList');
|
|
if (!listContainer) return; // Safety check
|
|
|
|
listContainer.innerHTML = ""; // Hapus data dummy statis
|
|
|
|
players.forEach((player, index) => {
|
|
const rank = index + 1;
|
|
let rankClass = 'rank-other';
|
|
|
|
// Tentukan styling berdasarkan ranking
|
|
if (rank === 1) rankClass = 'rank-1';
|
|
else if (rank === 2) rankClass = 'rank-2';
|
|
else if (rank === 3) rankClass = 'rank-3';
|
|
|
|
// Format angka skor dengan koma (contoh: 1,000)
|
|
// Fallback jika score tidak valid
|
|
const scoreVal = parseInt(player.score) || 0;
|
|
const formattedScore = new Intl.NumberFormat().format(scoreVal);
|
|
|
|
const itemHtml = `
|
|
<li class="leaderboard-item ${rankClass}">
|
|
<div class="rank-badge">${rank}</div>
|
|
<div class="player-info">
|
|
<div class="player-name">${escapeHtml(player.username)}</div>
|
|
</div>
|
|
<div class="player-score">
|
|
<div class="score-value">${formattedScore}</div>
|
|
<div class="score-label">Points</div>
|
|
</div>
|
|
</li>
|
|
`;
|
|
|
|
listContainer.insertAdjacentHTML('beforeend', itemHtml);
|
|
});
|
|
}
|
|
|
|
// Mencegah XSS attack (keamanan tambahan)
|
|
function escapeHtml(text) {
|
|
if (!text) return text;
|
|
return text
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
} |