Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

MediaWiki:Common.js: Difference between revisions

MediaWiki interface page
No edit summary
No edit summary
Line 1: Line 1:
/* Any JavaScript here will be loaded for all users on every page load. */// Load DataTables library
/* Any JavaScript here will be loaded for all users on every page load. */// Load DataTables library
/* Any JavaScript here will be loaded for all users on every page load. */


mw.hook('wikipage.content').add(function ($content) {
mw.hook('wikipage.content').add(function ($content) {
Line 7: Line 8:
});
});


// Auto-embed X/Twitter status links into live tweets (no extension required)
(function () {
  'use strict';


  // Options you can tweak
/* ===========================
  var TW_OPTIONS = {
  Dungeon Speedrun Leaderboard
    // theme: 'dark',            // uncomment for dark
  =========================== */
    // conversation: 'none',    // hide reply thread
    // dnt: true,                // "Do Not Track"
    // align: 'center'          // center the embed
  };


  function loadXWidgets (cb) {
mw.hook('wikipage.content').add(function () {
    // If the widget API is ready, go
    if (window.twttr && twttr.widgets) { cb(); return; }


    // Already loading?
  function parseTime(t) {
    if (document.querySelector('script[src*="platform.twitter.com/widgets.js"]')) {
    if (!t || !t.includes(":")) return 999999;
      // Poll until ready
     const parts = t.trim().split(":");
      var tries = 0, t = setInterval(function () {
     return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10);
        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;
    SOLO TABLE
    =========================== */


    loadXWidgets(function () {
  const table = document.getElementById("leaderboardTable");
      anchors.forEach(function (a) {
        if (a.dataset.tweetEmbedded === '1') return; // avoid duplicates
        a.dataset.tweetEmbedded = '1';


        // Extract the numeric tweet ID
  if (table) {
        var match = a.href.match(/\/status\/(\d+)/);
        if (!match) return;
        var id = match[1];


        // Create a container after the link
    const container = document.getElementById("filterContainer");
        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) {
     if (container) {


Line 118: Line 46:
       const dungeons = [
       const dungeons = [
         "All",
         "All",
         "Wolf's Den", "Wolf's Den II", "Wolf's Den III",
         "Wolf's Den","Wolf's Den II","Wolf's Den III",
         "The Red Nest", "For The Eggs",
         "The Red Nest","For The Eggs",
         "Scarlet Revenge", "Scarlet Revenge II",
         "Scarlet Revenge","Scarlet Revenge II",
         "Promised One", "Promised One II", "Promised One III",
         "Promised One","Promised One II","Promised One III",
         "Lost and Found", "The Hostage", "Cactus On Fire",
         "Lost and Found","The Hostage","Cactus On Fire",
         "Deep Echoes", "Deep Echoes II", "Deep Echoes III", "King's Hoard" , "King's Hoard II",
         "Deep Echoes","Deep Echoes II","Deep Echoes III",
         "Hall of Daggers",
        "King's Hoard","King's Hoard II",
         "Hall of Daggers"
       ];
       ];


Line 148: Line 77:
       container.appendChild(wrapper);
       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() {
       function sortAndRank() {
         const rows = Array.from(table.querySelectorAll("tr")).slice(1);
         const rows = Array.from(table.querySelectorAll("tr")).slice(1);
         rows.sort((a, b) => {
 
         rows.sort((a,b) => {
 
           const dungeonA = a.cells[1].innerText.trim();
           const dungeonA = a.cells[1].innerText.trim();
           const dungeonB = b.cells[1].innerText.trim();
           const dungeonB = b.cells[1].innerText.trim();
           if (dungeonA < dungeonB) return -1;
           if (dungeonA < dungeonB) return -1;
           if (dungeonA > dungeonB) return 1;
           if (dungeonA > dungeonB) return 1;
           return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText);
           return parseTime(a.cells[4].innerText) - parseTime(b.cells[4].innerText);
         });
         });
         rows.forEach(row => table.appendChild(row));
         rows.forEach(row => table.appendChild(row));


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


       function filterTable() {
       function filterTable() {
         const selectedDungeon = dungeonSelect.value;
         const selectedDungeon = dungeonSelect.value;
         const playerSearch = playerInput.value.toLowerCase();
         const playerSearch = playerInput.value.toLowerCase();
         const rows = Array.from(table.querySelectorAll("tr")).slice(1);
         const rows = Array.from(table.querySelectorAll("tr")).slice(1);
         rows.forEach(row => {
         rows.forEach(row => {
           const dungeon = row.cells[1].innerText.trim();
           const dungeon = row.cells[1].innerText.trim();
           const player = row.cells[2].innerText.toLowerCase();
           const player = row.cells[2].innerText.toLowerCase();
           row.style.display =
           row.style.display =
             (selectedDungeon === "All" || dungeon === selectedDungeon) &&
             (selectedDungeon === "All" || dungeon === selectedDungeon) &&
             player.includes(playerSearch) ? "" : "none";
             player.includes(playerSearch)
              ? ""
              : "none";
 
         });
         });
        sortAndRank();
 
       }
       }


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


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


Line 218: Line 175:
       const dungeons = [
       const dungeons = [
         "All",
         "All",
         "Wolf's Den", "Wolf's Den II", "Wolf's Den III",
         "Wolf's Den","Wolf's Den II","Wolf's Den III",
         "The Red Nest", "For The Eggs",
         "The Red Nest","For The Eggs",
         "Scarlet Revenge", "Scarlet Revenge II",
         "Scarlet Revenge","Scarlet Revenge II",
         "Promised One", "Promised One II", "Promised One III",
         "Promised One","Promised One II","Promised One III",
         "Lost and Found", "The Hostage", "Cactus On Fire",
         "Lost and Found","The Hostage","Cactus On Fire",
         "Deep Echoes", "Deep Echoes II", "Deep Echoes III", "King's Hoard", "King's Hoard II",
         "Deep Echoes","Deep Echoes II","Deep Echoes III",
         "Hall of Daggers",
        "King's Hoard","King's Hoard II",
         "Hall of Daggers"
       ];
       ];


Line 248: Line 206:
       partyContainer.appendChild(wrapper);
       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() {
       function sortAndRankParty() {
         const rows = Array.from(partyTable.querySelectorAll("tr")).slice(1);
         const rows = Array.from(partyTable.querySelectorAll("tr")).slice(1);
         rows.sort((a, b) => {
 
         rows.sort((a,b) => {
 
           const dungeonA = a.cells[1].innerText.trim();
           const dungeonA = a.cells[1].innerText.trim();
           const dungeonB = b.cells[1].innerText.trim();
           const dungeonB = b.cells[1].innerText.trim();
           if (dungeonA < dungeonB) return -1;
           if (dungeonA < dungeonB) return -1;
           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);
           return parseTime(a.cells[5].innerText) - parseTime(b.cells[5].innerText);
         });
         });
         rows.forEach(row => partyTable.appendChild(row));
         rows.forEach(row => partyTable.appendChild(row));


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


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


       dungeonSelect.addEventListener("change", filterPartyTable);
       dungeonSelect.addEventListener("change", filterPartyTable);
       playerInput.addEventListener("input", filterPartyTable);
       playerInput.addEventListener("input", filterPartyTable);
       sortAndRankParty();
       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");
  });
});
});