MediaWiki:Common.js: Difference between revisions
MediaWiki interface page
More actions
No edit summary |
No edit summary |
||
| Line 45: | Line 45: | ||
filterWrapper.style.marginBottom = "20px"; | filterWrapper.style.marginBottom = "20px"; | ||
const | const title = document.createElement("h3"); | ||
title.innerText = "🔍 Filter Runs"; | |||
filterWrapper.appendChild( | filterWrapper.appendChild(title); | ||
const dungeonSelect = document.createElement("select"); | const dungeonSelect = document.createElement("select"); | ||
dungeonSelect.style.marginRight = " | dungeonSelect.style.marginRight = "10px"; | ||
[ | [ | ||
| Line 96: | Line 96: | ||
return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText); | return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText); | ||
}); | }); | ||
| Line 149: | Line 150: | ||
const rank = parseInt(row.cells[0]?.innerText); | const rank = parseInt(row.cells[0]?.innerText); | ||
if (!dungeon || !player || !time || | if (!dungeon || !player || !time) return; | ||
/* =========================== | |||
POINTS | |||
=========================== */ | |||
if (!isNaN(rank)) { | |||
playerPoints[player] = (playerPoints[player] || 0) + getPoints(rank); | |||
} | |||
/* | /* =========================== | ||
WORLD RECORDS (FIXED) | |||
=========================== */ | |||
const newTime = parseTime(time); | |||
if (!records[dungeon]) { | if (!records[dungeon]) { | ||
records[dungeon] = { time, players: [player] }; | records[dungeon] = { | ||
} else if (time === records[dungeon]. | time: time, | ||
seconds: newTime, | |||
players: [player] | |||
}; | |||
} else { | |||
if (newTime < records[dungeon].seconds) { | |||
records[dungeon] = { | |||
time: time, | |||
seconds: newTime, | |||
players: [player] | |||
}; | |||
} else if (newTime === records[dungeon].seconds) { | |||
records[dungeon].players.push(player); | |||
} | |||
} | } | ||
| Line 178: | Line 203: | ||
/* =========================== | /* =========================== | ||
COMPETITION | COMPETITION TABLE | ||
=========================== */ | =========================== */ | ||
| Line 227: | Line 252: | ||
`; | `; | ||
compTable.appendChild(row); | compTable.appendChild(row); | ||
}); | }); | ||
| Line 233: | Line 259: | ||
/* =========================== | /* =========================== | ||
WORLD | WORLD RECORD TABLE | ||
=========================== */ | =========================== */ | ||
| Line 256: | Line 282: | ||
Object.entries(records).forEach(([d, data]) => { | Object.entries(records).forEach(([d, data]) => { | ||
const row = document.createElement("tr"); | const row = document.createElement("tr"); | ||
row.innerHTML = ` | row.innerHTML = ` | ||
<td>${d}</td> | <td>${d}</td> | ||
| Line 262: | Line 290: | ||
<td>${data.players.join(", ")}</td> | <td>${data.players.join(", ")}</td> | ||
`; | `; | ||
wrTable.appendChild(row); | wrTable.appendChild(row); | ||
}); | }); | ||
| Line 280: | Line 310: | ||
/* =========================== | /* =========================== | ||
FILTER | FILTER | ||
=========================== */ | =========================== */ | ||
Revision as of 15:05, 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');
});
});
mw.hook('wikipage.content').add(function () {
/* ===========================
HELPERS
=========================== */
function parseTime(t) {
if (!t || !t.includes(":")) return 999999;
const [m, s] = t.trim().split(":").map(Number);
return m * 60 + s;
}
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;
}
/* ===========================
MAIN TABLE
=========================== */
const table = document.getElementById("leaderboardTable");
if (!table) return;
/* ===========================
FILTER UI
=========================== */
const filterWrapper = document.createElement("div");
filterWrapper.style.marginBottom = "20px";
const title = document.createElement("h3");
title.innerText = "🔍 Filter Runs";
filterWrapper.appendChild(title);
const dungeonSelect = document.createElement("select");
dungeonSelect.style.marginRight = "10px";
[
"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"
].forEach(name => {
const opt = document.createElement("option");
opt.value = name;
opt.textContent = name;
dungeonSelect.appendChild(opt);
});
filterWrapper.appendChild(document.createTextNode("Dungeon: "));
filterWrapper.appendChild(dungeonSelect);
const playerInput = document.createElement("input");
playerInput.placeholder = "Search player...";
playerInput.style.marginLeft = "10px";
filterWrapper.appendChild(playerInput);
/* ===========================
SORT + RANK
=========================== */
function sortAndRank() {
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
rows.sort((a,b) => {
if (a.cells.length < 5 || b.cells.length < 5) return 0;
const dA = a.cells[1].innerText.trim();
const dB = b.cells[1].innerText.trim();
if (dA !== dB) return dA.localeCompare(dB);
return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText);
});
rows.forEach(r => table.appendChild(r));
let currentDungeon = "";
let position = 0;
let rank = 0;
let prevTime = null;
rows.forEach(row => {
if (row.cells.length < 5) return;
const dungeon = row.cells[1].innerText.trim();
const time = parseTime(row.cells[4].innerText);
if (dungeon !== currentDungeon) {
currentDungeon = dungeon;
position = 1;
rank = 1;
prevTime = time;
} else {
position++;
if (time !== prevTime) rank = position;
prevTime = time;
}
row.cells[0].innerText = rank;
});
}
/* ===========================
BUILD TOP SECTION
=========================== */
function buildTopSection() {
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
const playerPoints = {};
const records = {};
rows.forEach(row => {
if (row.cells.length < 5) return;
const dungeon = row.cells[1]?.innerText?.trim();
const player = row.cells[2]?.innerText?.trim();
const time = row.cells[4]?.innerText?.trim();
const rank = parseInt(row.cells[0]?.innerText);
if (!dungeon || !player || !time) return;
/* ===========================
POINTS
=========================== */
if (!isNaN(rank)) {
playerPoints[player] = (playerPoints[player] || 0) + getPoints(rank);
}
/* ===========================
WORLD RECORDS (FIXED)
=========================== */
const newTime = parseTime(time);
if (!records[dungeon]) {
records[dungeon] = {
time: time,
seconds: newTime,
players: [player]
};
} else {
if (newTime < records[dungeon].seconds) {
records[dungeon] = {
time: time,
seconds: newTime,
players: [player]
};
} else if (newTime === records[dungeon].seconds) {
records[dungeon].players.push(player);
}
}
});
/* REMOVE OLD */
const existing = document.getElementById("topSection");
if (existing) existing.remove();
/* FLEX CONTAINER */
const top = document.createElement("div");
top.id = "topSection";
top.style.display = "flex";
top.style.gap = "30px";
top.style.marginBottom = "25px";
/* ===========================
COMPETITION TABLE
=========================== */
const compBox = document.createElement("div");
compBox.style.flex = "1";
const compTitle = document.createElement("h2");
compTitle.innerText = "🏆 Competition Leaderboard";
compBox.appendChild(compTitle);
const compTable = document.createElement("table");
compTable.className = "wikitable";
compTable.style.width = "100%";
compTable.innerHTML = `
<tr>
<th>Rank</th>
<th>Player</th>
<th>Points</th>
</tr>
`;
const leaderboard = Object.entries(playerPoints)
.map(([player, points]) => ({player, points}))
.sort((a,b)=>b.points-a.points);
let prevPoints = null;
let rank = 0;
let position = 0;
leaderboard.forEach(entry => {
position++;
if (entry.points !== prevPoints) rank = position;
prevPoints = entry.points;
const medal =
rank===1?"🥇 1":
rank===2?"🥈 2":
rank===3?"🥉 3":
rank;
const row = document.createElement("tr");
row.innerHTML = `
<td>${medal}</td>
<td>${entry.player}</td>
<td>${entry.points}</td>
`;
compTable.appendChild(row);
});
compBox.appendChild(compTable);
/* ===========================
WORLD RECORD TABLE
=========================== */
const wrBox = document.createElement("div");
wrBox.style.flex = "1";
const wrTitle = document.createElement("h2");
wrTitle.innerText = "🏆 Dungeon World Records";
wrBox.appendChild(wrTitle);
const wrTable = document.createElement("table");
wrTable.className = "wikitable";
wrTable.style.width = "100%";
wrTable.innerHTML = `
<tr>
<th>Dungeon</th>
<th>Time</th>
<th>Player(s)</th>
</tr>
`;
Object.entries(records).forEach(([d, data]) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${d}</td>
<td>${data.time}</td>
<td>${data.players.join(", ")}</td>
`;
wrTable.appendChild(row);
});
wrBox.appendChild(wrTable);
/* COMBINE */
top.appendChild(compBox);
top.appendChild(wrBox);
table.parentNode.insertBefore(top, table);
/* FILTER BELOW */
table.parentNode.insertBefore(filterWrapper, table);
}
/* ===========================
FILTER
=========================== */
function filterTable() {
const dungeon = dungeonSelect.value;
const player = playerInput.value.toLowerCase();
const rows = Array.from(table.querySelectorAll("tr")).slice(1);
rows.forEach(row => {
if (row.cells.length < 5) return;
const d = row.cells[1].innerText.trim();
const p = row.cells[2].innerText.toLowerCase();
row.style.display =
(dungeon === "All" || d === dungeon) &&
p.includes(player)
? ""
: "none";
});
}
dungeonSelect.addEventListener("change", filterTable);
playerInput.addEventListener("input", filterTable);
/* ===========================
INIT
=========================== */
sortAndRank();
buildTopSection();
});