Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
Revision as of 22:33, 5 March 2026 by QTPi (talk | contribs)

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 Speedrun Leaderboard
   Per-Dungeon Ranking + Filters
   =========================== */

mw.hook('wikipage.content').add(function () {

  // ===== SOLO TABLE =====
  const table = document.getElementById("leaderboardTable");
  if (table) {
    const container = document.getElementById("filterContainer");
    if (container) {

      const wrapper = document.createElement("div");
      wrapper.style.marginBottom = "15px";

      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",
        "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);

      container.appendChild(wrapper);

      function parseTime(t) {
        if (!t || !t.includes(":")) return 999999;
        const parts = t.trim().split(":");
        return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10);
      }

      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;
        rows.forEach(row => {
          if (row.style.display === "none") return;
          const dungeon = row.cells[1].innerText.trim();
          const rankCell = row.cells[0];
          if (dungeon !== currentDungeon) { currentDungeon = dungeon; dungeonRank = 1; }
          else { dungeonRank++; }
          if (dungeonRank === 1) rankCell.innerHTML = "🥇 1";
          else if (dungeonRank === 2) rankCell.innerHTML = "🥈 2";
          else if (dungeonRank === 3) rankCell.innerHTML = "🥉 3";
          else rankCell.innerText = dungeonRank;
        });
      }

      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";
        });
        sortAndRank();
      }

      dungeonSelect.addEventListener("change", filterTable);
      playerInput.addEventListener("input", filterTable);
      sortAndRank();
    }
  }

  // ===== PARTY TABLE =====
  const partyTable = document.getElementById("partyLeaderboardTable");
  if (partyTable) {
    const partyContainer = document.getElementById("partyFilterContainer");
    if (partyContainer) {

      const wrapper = document.createElement("div");
      wrapper.style.marginBottom = "15px";

      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",
        "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 = "Players: ";
      wrapper.appendChild(playerLabel);

      const playerInput = document.createElement("input");
      playerInput.type = "text";
      playerInput.placeholder = "Search player name...";
      playerInput.style.padding = "4px";
      wrapper.appendChild(playerInput);

      partyContainer.appendChild(wrapper);

      function parseTime(t) {
        if (!t || !t.includes(":")) return 999999;
        const parts = t.trim().split(":");
        return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10);
      }

      function sortAndRankParty() {
        const rows = Array.from(partyTable.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;
          // Time is now column 5 (0-indexed) because of the extra Party Size column
          return parseTime(a.cells[5].innerText) - parseTime(b.cells[5].innerText);
        });
        rows.forEach(row => partyTable.appendChild(row));

        let currentDungeon = "";
        let dungeonRank = 0;
        rows.forEach(row => {
          if (row.style.display === "none") return;
          const dungeon = row.cells[1].innerText.trim();
          const rankCell = row.cells[0];
          if (dungeon !== currentDungeon) { currentDungeon = dungeon; dungeonRank = 1; }
          else { dungeonRank++; }
          if (dungeonRank === 1) rankCell.innerHTML = "🥇 1";
          else if (dungeonRank === 2) rankCell.innerHTML = "🥈 2";
          else if (dungeonRank === 3) rankCell.innerHTML = "🥉 3";
          else rankCell.innerText = dungeonRank;
        });
      }

      function filterPartyTable() {
        const selectedDungeon = dungeonSelect.value;
        const playerSearch = playerInput.value.toLowerCase();
        const rows = Array.from(partyTable.querySelectorAll("tr")).slice(1);
        rows.forEach(row => {
          const dungeon = row.cells[1].innerText.trim();
          // Players column is now index 3
          const player = row.cells[3].innerText.toLowerCase();
          row.style.display =
            (selectedDungeon === "All" || dungeon === selectedDungeon) &&
            player.includes(playerSearch) ? "" : "none";
        });
        sortAndRankParty();
      }

      dungeonSelect.addEventListener("change", filterPartyTable);
      playerInput.addEventListener("input", filterPartyTable);
      sortAndRankParty();
    }
  }

});

/* Open YouTube links in new tab */
mw.hook('wikipage.content').add(function ($content) {
  $content.find('a[href*="youtube.com"], a[href*="youtu.be"]').each(function () {
    this.setAttribute("target", "_blank");
    this.setAttribute("rel", "noopener noreferrer");
  });
});