Created
May 7, 2023 01:03
-
-
Save NotArchon/fbfafc03f0e86c8a4f2a40fb3725fc5d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HiscoresCol { | |
name; | |
rowConsumer; | |
constructor(name, rowConsumer) { | |
this.name = name; | |
this.rowConsumer = rowConsumer; | |
} | |
} | |
class Hiscores { | |
page; | |
time; | |
gameMode; | |
xpMode; | |
accBuild; | |
category; | |
initiated; | |
selectAll(query) { | |
return document.querySelectorAll("#hiscores " + query); | |
} | |
select(query) { | |
return document.querySelector("#hiscores " + query); | |
} | |
selectNamed(query, name) { | |
return this.select(query + "[name='" + name + "']"); | |
} | |
init() { | |
this.page = ${queryPage}; | |
this.initCountdowns(); | |
this.initDropdowns(); | |
this.initCategories(); | |
this.initiated = true; | |
this.fetch(); | |
this.select(".rank-table").classList.remove("visually-hidden"); | |
} | |
initCountdowns() { | |
this.time = '${queryTime}'; | |
let weekResetMs = ${weekResetMs?long?c}; | |
let monthResetMs = ${monthResetMs?long?c}; | |
const updateTimers = () => { | |
this.select(".weekly-countdown").innerText = dhms(weekResetMs); | |
this.select(".monthly-countdown").innerText = dhms(monthResetMs); | |
}; | |
updateTimers(); | |
setInterval(() => { | |
weekResetMs = Math.max(0, weekResetMs - 1000); | |
monthResetMs = Math.max(0, monthResetMs - 1000); | |
updateTimers(); | |
}, 1000); | |
let activeLink; | |
let activeCountdown; | |
const selectTime = (time, link) => { | |
this.time = time; | |
if (activeCountdown) { | |
activeCountdown.classList.add("visually-hidden"); | |
activeCountdown = null; | |
} | |
if (time === "weekly" || time === "monthly") { | |
activeCountdown = this.select("." + time + "-countdown"); | |
activeCountdown.classList.remove("visually-hidden"); | |
} | |
if (activeLink) | |
activeLink.classList.remove("active"); | |
activeLink = link; | |
activeLink.classList.add("active"); | |
this.fetch(); | |
}; | |
const allTimeLink = this.select(".all-time-link"); | |
overwriteClick(allTimeLink, e => selectTime("all", allTimeLink)); | |
const weeklyLink = this.select(".weekly-link"); | |
overwriteClick(weeklyLink, e => selectTime("weekly", weeklyLink)); | |
const monthlyLink = this.select(".monthly-link"); | |
overwriteClick(monthlyLink, e => selectTime("monthly", monthlyLink)); | |
if (this.time === "weekly") | |
weeklyLink.click(); | |
else if (this.time === "monthly") | |
monthlyLink.click(); | |
else | |
allTimeLink.click(); | |
} | |
initDropdowns() { | |
/* game mode */ | |
this.gameMode = '${queryGameMode}'; | |
const gameModes = JSON.parse(`${gameModesJson}`); | |
const gameModesSelect = this.selectNamed("select", "game-mode"); | |
gameModesSelect.innerHTML = '<option value="all" selected>Game Mode - All</option>'; | |
gameModes.forEach(m => { | |
gameModesSelect.innerHTML += '<option value=' + m.key + (this.gameMode === m.key ? " selected" : "") + '>' | |
+ 'Game Mode - ' + m.name + '</option>'; | |
}); | |
gameModesSelect.addEventListener('change', e => { | |
this.gameMode = e.target.value; | |
this.fetch(); | |
}); | |
/* xp mode */ | |
this.xpMode = '${queryXpMode}'; | |
const xpModes = JSON.parse(`${xpModesJson}`); | |
const xpModesSelect = this.selectNamed("select", "xp-mode"); | |
xpModesSelect.innerHTML = '<option value="all" selected>XP Mode - All</option>'; | |
xpModes.forEach(m => { | |
xpModesSelect.innerHTML += '<option value=' + m.key + (this.xpMode === m.key ? " selected" : "") + '>' | |
+ 'XP Mode - ' + m.name + '</option>'; | |
}); | |
xpModesSelect.addEventListener('change', e => { | |
this.xpMode = e.target.value; | |
this.fetch(); | |
}); | |
/* account build */ | |
this.accBuild = '${queryAccBuild}'; | |
const accBuilds = JSON.parse(`${accBuildsJson}`); | |
const accBuildsSelect = this.selectNamed("select", "acc-build"); | |
accBuildsSelect.innerHTML = '<option value="all" selected>Build - All</option>'; | |
accBuilds.forEach(m => { | |
accBuildsSelect.innerHTML += '<option value=' + m.key + (this.accBuild === m.key ? " selected" : "") + '>' | |
+ 'Build - ' + m.name + '</option>'; | |
}); | |
accBuildsSelect.addEventListener('change', e => { | |
this.accBuild = e.target.value; | |
this.fetch(); | |
}); | |
} | |
initCategories() { | |
this.category = '${queryCategory}'; | |
const categories = this.selectAll("ul.hiscores-categories li a"); | |
let active; | |
let iconClass; | |
categories.forEach(a => { | |
const i = a.href.indexOf("#"); | |
if (i === -1) return; | |
const category = a.href.substring(i + 1); | |
overwriteClick(a, e => { | |
if (category === "votes-all") { | |
this.gameMode = "all"; | |
this.selectNamed("select", "game-mode").selectedIndex = 0; | |
Object.values(this.selectNamed("select", "game-mode").options).forEach(op => op.disabled = true); | |
this.xpMode = "all"; | |
this.selectNamed("select", "xp-mode").selectedIndex = 0; | |
Object.values(this.selectNamed("select", "xp-mode").options).forEach(op => op.disabled = true); | |
this.accBuild = "all"; | |
this.selectNamed("select", "acc-build").selectedIndex = 0; | |
Object.values(this.selectNamed("select", "acc-build").options).forEach(op => op.disabled = true); | |
} else { | |
Object.values(this.selectNamed("select", "game-mode").options).forEach(op => op.disabled = false); | |
Object.values(this.selectNamed("select", "xp-mode").options).forEach(op => op.disabled = false); | |
Object.values(this.selectNamed("select", "acc-build").options).forEach(op => op.disabled = false); | |
} | |
if (active) { | |
this.page = 1; | |
active.classList.remove("active"); | |
this.select(".card .highscores-current-view").scrollIntoView(); | |
} | |
a.classList.add("active"); | |
active = a; | |
this.select(".category-name-text").innerText = a.innerText; | |
const catNameElement = this.select(".category-name"); | |
if (iconClass) { | |
catNameElement.classList.remove(iconClass); | |
iconClass = null; | |
} | |
iconClass = a.classList.item(0); // meh | |
catNameElement.classList.add(iconClass); | |
this.category = category; | |
this.fetch(); | |
}); | |
if (this.category === category) { | |
a.click(); | |
} | |
}); | |
} | |
fetch() { | |
if (!this.initiated) | |
return; | |
const page = this.page; | |
const time = this.time; | |
const gameMode = this.gameMode; | |
const xpMode = this.xpMode; | |
const accBuild = this.accBuild; | |
const category = this.category; | |
const data = new Map(); | |
data.set("g", gameMode); | |
data.set("x", xpMode); | |
data.set("b", accBuild); | |
data.set("c", category); | |
data.set("p", page); | |
data.set("t", time); | |
const table = this.select(".rank-table"); | |
table.style.opacity = 0.25; | |
sendRequest("POST", "/detectbots/hiscores/fetch", data, (success, message) => { | |
if (this.page !== page || this.time !== time | |
|| this.gameMode !== gameMode || this.xpMode !== xpMode || this.accBuild !== accBuild | |
|| this.category !== category) | |
return; // this is an old request that took some time to load most likely | |
this.populate(success, message); | |
table.style.opacity = 1; | |
}); | |
} | |
populate(success, message) { | |
const header = this.select(".hiscores-header"); | |
header.innerHTML = ''; | |
const tbody = this.select("#leaderboard tbody"); | |
if (success !== true) { | |
tbody.innerHTML = message; | |
return; | |
} | |
tbody.innerHTML = ''; | |
const rows = JSON.parse(message); | |
const columns = []; | |
let dropdownsDisabled = false; | |
if (this.category.startsWith("skill-")) { | |
if (this.time === "all") { | |
columns.push(new HiscoresCol("Level", r => r.primary)); | |
columns.push(new HiscoresCol("Experience", r => r.secondary.toLocaleString())); | |
} else { | |
columns.push(new HiscoresCol("XP Gained", r => r.secondary.toLocaleString())); | |
} | |
} else if (this.category === "votes-all") { | |
dropdownsDisabled = true; | |
columns.push(new HiscoresCol("Count", r => r.primary)); | |
} else if (this.category === "wilderness-kd") { | |
columns.push(new HiscoresCol("Kills", r => r.primary)); | |
columns.push(new HiscoresCol("Deaths", r => r.secondary)); | |
columns.push(new HiscoresCol("KDR", r => r.secondary === 0 ? (r.primary + '.00') : (r.primary / r.secondary).toFixed(2))); | |
} else if (this.category === "task-counts") { | |
columns.push(new HiscoresCol("Completed", r => r.primary)); | |
columns.push(new HiscoresCol("Points", r => r.secondary)); | |
} else if (this.category === "login-streak") { | |
columns.push(new HiscoresCol("Longest", r => r.primary)); | |
} else if (this.category === "barrows") { | |
columns.push(new HiscoresCol("Chests", r => r.primary)); | |
} else if (this.category.startsWith("kc-")) { | |
columns.push(new HiscoresCol("Kills", r => r.primary)); | |
} else { // assuming only one value | |
columns.push(new HiscoresCol("Count", r => r.primary)); | |
} | |
header.innerHTML = '<th class="rank">Rank</th><th class="username">Name</th>'; | |
columns.forEach(c => header.innerHTML += '<th>' + c.name + '</th>'); | |
tbody.innerHTML = ''; | |
rows.forEach(r => { | |
const rank = r.rank; | |
let rankClass; | |
if (rank === 1) | |
rankClass = "first"; | |
else if (rank === 2) | |
rankClass = "second"; | |
else if (rank === 3) | |
rankClass = "third"; | |
rankClass = rankClass ? (" " + rankClass) : ""; | |
let s = '<tr>'; | |
s += '<td class="rank' + rankClass + '">' + rank + '</td>'; | |
s += '<td class="username' + rankClass + '"><a href="/hiscores/player/Jane">' | |
+ r.name + '</a></td>'; | |
columns.forEach(c => s += '<td class="hiscores-value">' + c.rowConsumer(r) + '</td>'); | |
s += '</tr>'; | |
tbody.innerHTML += s; | |
}); | |
this.updatePagination(); | |
} | |
updatePagination() { | |
const changePage = p => { | |
if(p > 0 && p !== this.page) { | |
this.page = p; | |
this.fetch(); | |
} | |
}; | |
const pageStart = 1 + (Math.floor((this.page - 1) / 3) * 3); | |
for(let i = 0; i < 3; i++) { | |
const pageItem = this.select(".page-item-" + (i + 1)); | |
const pageLink = this.select(".page-item-" + (i + 1) + " a"); | |
const p = pageStart + i; | |
if(p === this.page) | |
pageItem.classList.add("active"); | |
else | |
pageItem.classList.remove("active"); | |
pageLink.innerText = '' + p; | |
overwriteClick(pageItem, e => changePage(p)); | |
} | |
const first = this.select(".first-page-btn"); | |
const prev = this.select(".prev-page-btn"); | |
const next = this.select(".next-page-btn"); | |
if (this.page <= 1) { | |
prev.classList.add("disabled"); | |
first.classList.add("disabled"); | |
} else { | |
prev.classList.remove("disabled"); | |
first.classList.remove("disabled"); | |
overwriteClick(first, e => changePage(1)); | |
overwriteClick(prev, e => changePage(this.page - 1)); | |
} | |
overwriteClick(next, e => changePage(this.page + 1)); | |
} | |
} | |
try { | |
new Hiscores().init(); | |
} catch(err) { | |
if (devMode) | |
alert(err); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment