MediaWiki:Common.js
MediaWiki interface page
More actions
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */// Load DataTables library
mw.hook('wikipage.content').add(function ($content) {
$content.find('.spoiler').on('click', function () {
$(this).toggleClass('revealed');
});
});
// Auto-embed X/Twitter status links into live tweets (no extension required)
(function () {
'use strict';
// Options you can tweak
var TW_OPTIONS = {
// theme: 'dark', // uncomment for dark
// conversation: 'none', // hide reply thread
// dnt: true, // "Do Not Track"
// align: 'center' // center the embed
};
function loadXWidgets (cb) {
// If the widget API is ready, go
if (window.twttr && twttr.widgets) { cb(); return; }
// Already loading?
if (document.querySelector('script[src*="platform.twitter.com/widgets.js"]')) {
// Poll until ready
var tries = 0, t = setInterval(function () {
if (window.twttr && twttr.widgets) { clearInterval(t); cb(); }
else if (++tries > 40) { clearInterval(t); }
}, 250);
return;
}
// Inject the widgets.js script
var s = document.createElement('script');
s.async = true;
s.src = 'https://platform.twitter.com/widgets.js';
s.onload = function () { cb(); };
document.head.appendChild(s);
}
// Find eligible links and embed them
function embedLinks(root) {
var scope = root || document;
var selector = [
'a[href^="https://x.com/"][href*="/status/"]',
'a[href^="http://x.com/"][href*="/status/"]',
'a[href^="https://twitter.com/"][href*="/status/"]',
'a[href^="http://twitter.com/"][href*="/status/"]'
].join(',');
var anchors = scope.querySelectorAll(selector);
if (!anchors.length) return;
loadXWidgets(function () {
anchors.forEach(function (a) {
if (a.dataset.tweetEmbedded === '1') return; // avoid duplicates
a.dataset.tweetEmbedded = '1';
// Extract the numeric tweet ID
var match = a.href.match(/\/status\/(\d+)/);
if (!match) return;
var id = match[1];
// Create a container after the link
var container = document.createElement('div');
container.className = 'tweet-embed';
a.insertAdjacentElement('afterend', container);
// Ask widgets API to render
if (window.twttr && twttr.widgets && twttr.widgets.createTweet) {
twttr.widgets.createTweet(id, container, TW_OPTIONS).catch(function(){});
}
});
// Ensure any dynamically added blockquotes also render
if (window.twttr && twttr.widgets && twttr.widgets.load) {
twttr.widgets.load(scope);
}
});
}
// Run on page load and whenever VE/LQT/etc. inject content
if (window.mw && mw.hook) {
mw.hook('wikipage.content').add(function ($content) {
embedLinks($content && $content[0]);
});
} else {
document.addEventListener('DOMContentLoaded', function () { embedLinks(document); });
}
})();
/* ===========================
Dungeon Leaderboard Script
=========================== */
document.addEventListener("DOMContentLoaded", function () {
const table = document.getElementById("leaderboardTable");
if (!table) return; // Only run on leaderboard page
const dungeonFilter = document.getElementById("filterDungeon");
const typeFilter = document.getElementById("filterType");
const addBtn = document.getElementById("addRunBtn");
function parseTime(t) {
if (!t || !t.includes(":")) return 999999;
const parts = t.split(":");
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
function sortAndRank() {
const rows = Array.from(table.rows).slice(1);
rows.sort((a, b) => {
return parseTime(a.cells[6].innerText) - parseTime(b.cells[6].innerText);
});
rows.forEach(row => table.appendChild(row));
rows.forEach((row, index) => {
const rankCell = row.cells[0];
if (index === 0) rankCell.innerHTML = "🥇 1";
else if (index === 1) rankCell.innerHTML = "🥈 2";
else if (index === 2) rankCell.innerHTML = "🥉 3";
else rankCell.innerText = index + 1;
});
}
function filterTable() {
const selectedDungeon = dungeonFilter.value;
const selectedType = typeFilter.value;
Array.from(table.rows).slice(1).forEach(row => {
const dungeon = row.cells[1].innerText.trim();
const type = row.cells[2].innerText.trim();
const show =
(selectedDungeon === "All" || dungeon === selectedDungeon) &&
(selectedType === "All" || type === selectedType);
row.style.display = show ? "" : "none";
});
}
dungeonFilter.addEventListener("change", filterTable);
typeFilter.addEventListener("change", filterTable);
addBtn.addEventListener("click", function () {
const overlay = document.createElement("div");
overlay.style = `
position:fixed;
top:0;left:0;
width:100%;height:100%;
background:rgba(0,0,0,0.6);
display:flex;
align-items:center;
justify-content:center;
z-index:9999;
`;
const modal = document.createElement("div");
modal.style = `
background:white;
padding:20px;
width:420px;
border-radius:8px;
`;
modal.innerHTML = `
<h3>Submit Dungeon Run</h3>
<label>Dungeon:</label><br>
<select id="runDungeon">
<option>Wolf's Den</option>
<option>Wolf's Den II</option>
<option>Wolf's Den III</option>
<option>The Red Nest</option>
<option>For The Eggs</option>
<option>Scarlet Revenge</option>
<option>Scarlet Revenge II</option>
<option>Promised One</option>
<option>Promised One II</option>
<option>Promised One III</option>
<option>Lost and Found</option>
<option>The Hostage</option>
<option>Cactus On Fire</option>
<option>Deep Echoes</option>
<option>Deep Echoes II</option>
<option>Deep Echoes III</option>
</select><br><br>
<label>Type:</label><br>
<select id="runType">
<option value="Solo">Solo</option>
<option value="Party">Party</option>
</select><br><br>
<div id="partySizeSection" style="display:none;">
<label>Party Size:</label><br>
<select id="runPartySize">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select><br><br>
</div>
<div id="weaponSection">
<label>Weapon (Solo Only):</label><br>
<select id="runWeapon">
<option>Bow</option>
<option>Great Sword</option>
<option>Sword & Shield</option>
</select><br><br>
</div>
<label>Player / Party:</label><br>
<input type="text" id="runPlayer"><br><br>
<label>Time (MM:SS):</label><br>
<input type="text" id="runTime"><br><br>
<label>Date:</label><br>
<input type="text" id="runDate"><br><br>
<label>Screenshot:</label><br>
<small>Upload first via <a href="/wiki/Special:Upload" target="_blank">Upload File</a></small><br>
<input type="text" id="runScreenshot"><br><br>
<button id="submitRun">Generate Entry</button>
<button id="cancelRun">Cancel</button>
`;
overlay.appendChild(modal);
document.body.appendChild(overlay);
const runType = document.getElementById("runType");
const partySizeSection = document.getElementById("partySizeSection");
const weaponSection = document.getElementById("weaponSection");
runType.addEventListener("change", function() {
if (this.value === "Party") {
partySizeSection.style.display = "block";
weaponSection.style.display = "none";
} else {
partySizeSection.style.display = "none";
weaponSection.style.display = "block";
}
});
document.getElementById("cancelRun").onclick = () => {
document.body.removeChild(overlay);
};
document.getElementById("submitRun").onclick = function () {
const dungeon = document.getElementById("runDungeon").value;
const type = runType.value;
const partySize = type === "Solo" ? "1" : document.getElementById("runPartySize").value;
const weapon = type === "Solo" ? document.getElementById("runWeapon").value : "—";
const player = document.getElementById("runPlayer").value;
const time = document.getElementById("runTime").value;
const date = document.getElementById("runDate").value;
const screenshot = document.getElementById("runScreenshot").value;
if (!player || !time || !date || !screenshot) {
alert("All required fields must be completed.");
return;
}
const row = `
|-
|
| ${dungeon}
| ${type}
| ${partySize}
| ${player}
| ${weapon}
| ${time}
| ${date}
| [[File:${screenshot}|120px]]
`;
alert("Copy this row and paste at bottom of table:\\n\\n" + row);
document.body.removeChild(overlay);
};
});
sortAndRank();
});