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 30: Line 30:


     const container = document.getElementById("filterContainer");
     const container = document.getElementById("filterContainer");
    let wrapper; // <-- IMPORTANT (used later)


     if (container) {
     if (container) {


       const wrapper = document.createElement("div");
       wrapper = document.createElement("div");
       wrapper.style.marginBottom = "15px";
       wrapper.style.marginBottom = "15px";
      const label = document.createElement("h3");
      label.innerText = "🔍 Filter Runs";
      wrapper.appendChild(label);


       const dungeonLabel = document.createElement("strong");
       const dungeonLabel = document.createElement("strong");
Line 73: Line 79:
       playerInput.style.padding = "4px";
       playerInput.style.padding = "4px";
       wrapper.appendChild(playerInput);
       wrapper.appendChild(playerInput);
      container.appendChild(wrapper);




Line 121: Line 125:
           }
           }


          // ✅ Numbers only
           rankCell.innerText = dungeonRank;
           rankCell.innerText = dungeonRank;


Line 130: Line 133:


       /* ===========================
       /* ===========================
         FIXED COMPETITION LEADERBOARD
         COMPETITION LEADERBOARD
         =========================== */
         =========================== */


Line 168: Line 171:
         if (existing) existing.remove();
         if (existing) existing.remove();


         const container = document.createElement("div");
         const compContainer = document.createElement("div");
         container.id = "competitionLeaderboard";
         compContainer.id = "competitionLeaderboard";
         container.style.marginBottom = "20px";
         compContainer.style.marginBottom = "20px";


         const title = document.createElement("h2");
         const title = document.createElement("h2");
         title.innerText = "🏆 Competition Leaderboard";
         title.innerText = "🏆 Competition Leaderboard";
         container.appendChild(title);
         compContainer.appendChild(title);


         const tableEl = document.createElement("table");
         const tableEl = document.createElement("table");
Line 188: Line 191:
         `;
         `;


        // ✅ Proper competition ranking (ties handled)
         let prevPoints = null;
         let prevPoints = null;
         let rank = 0;
         let rank = 0;
Line 221: Line 223:
         });
         });


         container.appendChild(tableEl);
         compContainer.appendChild(tableEl);
         table.parentNode.insertBefore(container, table);
 
        // Insert leaderboard above table
         table.parentNode.insertBefore(compContainer, table);
 
        // Insert filters UNDER leaderboard
        compContainer.insertAdjacentElement("afterend", wrapper);


       }
       }
Line 254: Line 261:
       sortAndRank();
       sortAndRank();
       buildCompetitionLeaderboard();
       buildCompetitionLeaderboard();
     }
     }
   }
   }

Revision as of 14: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');
  });
});


/* ===========================
   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);
  }


  /* ===========================
     SOLO TABLE
     =========================== */

  const table = document.getElementById("leaderboardTable");

  if (table) {

    const container = document.getElementById("filterContainer");

    let wrapper; // <-- IMPORTANT (used later)

    if (container) {

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


      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;

        });

      }


      /* ===========================
         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);

        // Insert leaderboard above table
        table.parentNode.insertBefore(compContainer, table);

        // Insert filters UNDER leaderboard
        compContainer.insertAdjacentElement("afterend", wrapper);

      }


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

      sortAndRank();
      buildCompetitionLeaderboard();

    }
  }


  /* ===========================
     PARTY TABLE (unchanged)
     =========================== */

  const partyTable = document.getElementById("partyLeaderboardTable");

  if (partyTable) {

    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;

        return parseTime(a.cells[5].innerText) - parseTime(b.cells[5].innerText);

      });

      rows.forEach(row => partyTable.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[5].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;

      });

    }

    sortAndRankParty();
  }

});