MediaWiki:Common.js: Difference between revisions
MediaWiki interface page
More actions
No edit summary |
No edit summary |
||
| Line 19: | Line 19: | ||
return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10); | return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10); | ||
} | } | ||
const table = document.getElementById("leaderboardTable"); | const table = document.getElementById("leaderboardTable"); | ||
if (!table) return; | if (!table) return; | ||
/* =========================== | /* =========================== | ||
FILTER UI | |||
=========================== */ | =========================== */ | ||
| Line 127: | Line 125: | ||
}); | }); | ||
} | |||
/* =========================== | |||
WORLD RECORDS TABLE | |||
=========================== */ | |||
function buildWorldRecordsTable() { | |||
const rows = Array.from(table.querySelectorAll("tr")).slice(1); | |||
const records = {}; | |||
rows.forEach(row => { | |||
const dungeon = row.cells[1].innerText.trim(); | |||
const time = row.cells[4].innerText.trim(); | |||
const player = row.cells[2].innerText.trim(); | |||
if (!records[dungeon]) { | |||
records[dungeon] = { | |||
time: time, | |||
players: [player] | |||
}; | |||
} else { | |||
if (time === records[dungeon].time) { | |||
records[dungeon].players.push(player); | |||
} | |||
} | |||
}); | |||
const existing = document.getElementById("worldRecordsTable"); | |||
if (existing) existing.remove(); | |||
const container = document.createElement("div"); | |||
container.id = "worldRecordsTable"; | |||
container.style.marginBottom = "20px"; | |||
const title = document.createElement("h2"); | |||
title.innerText = "🏆 Dungeon World Records"; | |||
container.appendChild(title); | |||
const tableEl = document.createElement("table"); | |||
tableEl.className = "wikitable"; | |||
tableEl.style.width = "60%"; | |||
tableEl.innerHTML = ` | |||
<tr> | |||
<th>Dungeon</th> | |||
<th>Time</th> | |||
<th>Player(s)</th> | |||
</tr> | |||
`; | |||
Object.entries(records).forEach(([dungeon, data]) => { | |||
const row = document.createElement("tr"); | |||
row.innerHTML = ` | |||
<td>${dungeon}</td> | |||
<td>${data.time}</td> | |||
<td>${data.players.join(", ")}</td> | |||
`; | |||
tableEl.appendChild(row); | |||
}); | |||
container.appendChild(tableEl); | |||
table.parentNode.insertBefore(container, table); | |||
} | } | ||
| Line 166: | Line 237: | ||
.map(([player, points]) => ({ player, points })) | .map(([player, points]) => ({ player, points })) | ||
.sort((a, b) => b.points - a.points); | .sort((a, b) => b.points - a.points); | ||
const existing = document.getElementById("competitionLeaderboard"); | const existing = document.getElementById("competitionLeaderboard"); | ||
| Line 225: | Line 295: | ||
compContainer.appendChild(tableEl); | compContainer.appendChild(tableEl); | ||
table.parentNode.insertBefore(compContainer, table); | table.parentNode.insertBefore(compContainer, table); | ||
// Insert filters | // Insert filters UNDER leaderboard | ||
table.parentNode.insertBefore(wrapper, table); | table.parentNode.insertBefore(wrapper, table); | ||
| Line 235: | Line 304: | ||
/* =========================== | /* =========================== | ||
FILTER | |||
=========================== */ | =========================== */ | ||
| Line 269: | Line 338: | ||
sortAndRank(); | sortAndRank(); | ||
buildWorldRecordsTable(); | |||
buildCompetitionLeaderboard(); | buildCompetitionLeaderboard(); | ||
}); | }); | ||
Revision as of 14:50, 18 March 2026
/* Any JavaScript here will be loaded for all users on every page load. */
mw.hook('wikipage.content').add(function ($content) {
$content.find('.spoiler').on('click', function () {
$(this).toggleClass('revealed');
});
});
/* ===========================
Dungeon Speedrun Leaderboard
=========================== */
mw.hook('wikipage.content').add(function () {
function parseTime(t) {
if (!t || !t.includes(":")) return 999999;
const parts = t.trim().split(":");
return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10);
}
const table = document.getElementById("leaderboardTable");
if (!table) return;
/* ===========================
FILTER UI
=========================== */
const wrapper = document.createElement("div");
wrapper.style.marginBottom = "15px";
const label = document.createElement("h3");
label.innerText = "🔍 Filter Runs";
wrapper.appendChild(label);
const dungeonLabel = document.createElement("strong");
dungeonLabel.innerText = "Dungeon: ";
wrapper.appendChild(dungeonLabel);
const dungeonSelect = document.createElement("select");
dungeonSelect.style.marginRight = "20px";
const dungeons = [
"All",
"Wolf's Den","Wolf's Den II","Wolf's Den III",
"The Red Nest","For The Eggs",
"Scarlet Revenge","Scarlet Revenge II",
"Promised One","Promised One II","Promised One III",
"Lost and Found","The Hostage","Cactus On Fire",
"Deep Echoes","Deep Echoes II","Deep Echoes III",
"King's Hoard","King's Hoard II",
"Hall of Daggers"
];
dungeons.forEach(name => {
const option = document.createElement("option");
option.value = name;
option.textContent = name;
dungeonSelect.appendChild(option);
});
wrapper.appendChild(dungeonSelect);
const playerLabel = document.createElement("strong");
playerLabel.innerText = "Player: ";
wrapper.appendChild(playerLabel);
const playerInput = document.createElement("input");
playerInput.type = "text";
playerInput.placeholder = "Search player name...";
playerInput.style.padding = "4px";
wrapper.appendChild(playerInput);
/* ===========================
SORT + RANK
=========================== */
function sortAndRank() {
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
rows.sort((a,b) => {
const dungeonA = a.cells[1].innerText.trim();
const dungeonB = b.cells[1].innerText.trim();
if (dungeonA < dungeonB) return -1;
if (dungeonA > dungeonB) return 1;
return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText);
});
rows.forEach(row => table.appendChild(row));
let currentDungeon = "";
let dungeonRank = 0;
let prevTime = null;
let position = 0;
rows.forEach(row => {
const dungeon = row.cells[1].innerText.trim();
const time = parseTime(row.cells[4].innerText);
const rankCell = row.cells[0];
if (dungeon !== currentDungeon) {
currentDungeon = dungeon;
dungeonRank = 1;
position = 1;
prevTime = time;
} else {
position++;
if (time !== prevTime) {
dungeonRank = position;
}
prevTime = time;
}
rankCell.innerText = dungeonRank;
});
}
/* ===========================
WORLD RECORDS TABLE
=========================== */
function buildWorldRecordsTable() {
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
const records = {};
rows.forEach(row => {
const dungeon = row.cells[1].innerText.trim();
const time = row.cells[4].innerText.trim();
const player = row.cells[2].innerText.trim();
if (!records[dungeon]) {
records[dungeon] = {
time: time,
players: [player]
};
} else {
if (time === records[dungeon].time) {
records[dungeon].players.push(player);
}
}
});
const existing = document.getElementById("worldRecordsTable");
if (existing) existing.remove();
const container = document.createElement("div");
container.id = "worldRecordsTable";
container.style.marginBottom = "20px";
const title = document.createElement("h2");
title.innerText = "🏆 Dungeon World Records";
container.appendChild(title);
const tableEl = document.createElement("table");
tableEl.className = "wikitable";
tableEl.style.width = "60%";
tableEl.innerHTML = `
<tr>
<th>Dungeon</th>
<th>Time</th>
<th>Player(s)</th>
</tr>
`;
Object.entries(records).forEach(([dungeon, data]) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${dungeon}</td>
<td>${data.time}</td>
<td>${data.players.join(", ")}</td>
`;
tableEl.appendChild(row);
});
container.appendChild(tableEl);
table.parentNode.insertBefore(container, table);
}
/* ===========================
COMPETITION LEADERBOARD
=========================== */
function buildCompetitionLeaderboard() {
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
const playerPoints = {};
function getPoints(rank) {
const scoring = {
1: 25, 2: 20, 3: 17, 4: 15, 5: 13,
6: 11, 7: 10, 8: 9, 9: 8, 10: 7,
11: 6, 12: 5, 13: 4, 14: 3, 15: 2
};
return scoring[rank] || 1;
}
rows.forEach(row => {
const rank = parseInt(row.cells[0].innerText);
const player = row.cells[2].innerText.trim();
if (!player || isNaN(rank)) return;
const points = getPoints(rank);
playerPoints[player] = (playerPoints[player] || 0) + points;
});
const leaderboard = Object.entries(playerPoints)
.map(([player, points]) => ({ player, points }))
.sort((a, b) => b.points - a.points);
const existing = document.getElementById("competitionLeaderboard");
if (existing) existing.remove();
const compContainer = document.createElement("div");
compContainer.id = "competitionLeaderboard";
compContainer.style.marginBottom = "20px";
const title = document.createElement("h2");
title.innerText = "🏆 Competition Leaderboard";
compContainer.appendChild(title);
const tableEl = document.createElement("table");
tableEl.className = "wikitable";
tableEl.style.width = "50%";
tableEl.innerHTML = `
<tr>
<th>Rank</th>
<th>Player</th>
<th>Points</th>
</tr>
`;
let prevPoints = null;
let rank = 0;
let position = 0;
leaderboard.forEach((entry) => {
position++;
if (entry.points !== prevPoints) {
rank = position;
}
prevPoints = entry.points;
let displayRank;
if (rank === 1) displayRank = "🥇 1";
else if (rank === 2) displayRank = "🥈 2";
else if (rank === 3) displayRank = "🥉 3";
else displayRank = rank;
const row = document.createElement("tr");
row.innerHTML = `
<td>${displayRank}</td>
<td>${entry.player}</td>
<td>${entry.points}</td>
`;
tableEl.appendChild(row);
});
compContainer.appendChild(tableEl);
table.parentNode.insertBefore(compContainer, table);
// Insert filters UNDER leaderboard
table.parentNode.insertBefore(wrapper, table);
}
/* ===========================
FILTER
=========================== */
function filterTable() {
const selectedDungeon = dungeonSelect.value;
const playerSearch = playerInput.value.toLowerCase();
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
rows.forEach(row => {
const dungeon = row.cells[1].innerText.trim();
const player = row.cells[2].innerText.toLowerCase();
row.style.display =
(selectedDungeon === "All" || dungeon === selectedDungeon) &&
player.includes(playerSearch)
? ""
: "none";
});
}
dungeonSelect.addEventListener("change", filterTable);
playerInput.addEventListener("input", filterTable);
/* ===========================
INIT
=========================== */
sortAndRank();
buildWorldRecordsTable();
buildCompetitionLeaderboard();
});