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

Join the Playtest on Steam Now: SpiritVale

MediaWiki:Common.js

MediaWiki interface page

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. */

/*
  SpiritVale Skill Slider

  What this does:
  - Finds every skill card:        <div class="sv-skill-card" data-max-level="10" data-level="10">
  - Inserts a slider into:         <div class="sv-level-slider"></div>
  - Updates any element inside the card that has:
        data-series='["Lv1 text","Lv2 text", ...]'
    so that it shows the correct value for the chosen level.
*/

(function () {

  // Ensure a number stays between a minimum and maximum.
  function clampNumber(value, min, max) {
    var n = parseInt(value, 10);

    // If value is not a valid number, fall back to min.
    if (isNaN(n)) {
      return min;
    }

    if (n < min) return min;
    if (n > max) return max;
    return n;
  }

  // Initialize skill cards found under `root`.
  // `root` is usually the page, but MediaWiki sometimes gives us just a section of HTML.
  function initSkillCards(root) {
    var container = root || document;

    // Only pick cards we haven't initialized yet (data-sv-init is our marker).
    var cards = container.querySelectorAll(".sv-skill-card:not([data-sv-init])");

    cards.forEach(function (card) {
      // Read max level from HTML attribute (default 1 if missing).
      var maxLevel = clampNumber(card.getAttribute("data-max-level"), 1, 999);

      // If max level is 1, there's no reason to create a slider.
      if (maxLevel <= 1) {
        card.setAttribute("data-sv-init", "1");
        return;
      }

      // Read the starting level; if missing, default to max level.
      var startLevel = card.getAttribute("data-level");
      if (startLevel == null || startLevel === "") {
        startLevel = maxLevel;
      }
      startLevel = clampNumber(startLevel, 1, maxLevel);

      // Find where we should place the slider.
      var sliderHost = card.querySelector(".sv-level-slider");
      if (!sliderHost) {
        // No placeholder = nothing to do.
        card.setAttribute("data-sv-init", "1");
        return;
      }

      // Optional: element that shows the current level number in text.
      var levelNumberSpan = card.querySelector(".sv-level-num");

      // Find all dynamic elements that contain a data-series list.
      var dynamicElements = card.querySelectorAll("[data-series]");

      // Parse the JSON data-series once and store it on the element for reuse.
      dynamicElements.forEach(function (el) {
        var raw = el.getAttribute("data-series");
        try {
          el._svSeries = JSON.parse(raw);
        } catch (e) {
          el._svSeries = null;
        }
      });

      // Create the slider element.
      var slider = document.createElement("input");
      slider.type = "range";
      slider.min = "1";
      slider.max = String(maxLevel);
      slider.value = String(startLevel);
      slider.className = "sv-level-range";

      // Clear any existing content in the host, then add the slider.
      sliderHost.textContent = "";
      sliderHost.appendChild(slider);

      // Apply a given level to this card:
      // - update the level number text
      // - update all dynamic elements to show the correct series value
      function applyLevel(level) {
        var lv = clampNumber(level, 1, maxLevel);

        // Store the chosen level on the card (optional, but useful for debugging).
        card.setAttribute("data-level", String(lv));

        // Update the visible "current level" number if present.
        if (levelNumberSpan) {
          levelNumberSpan.textContent = String(lv);
        }

        // Update each dynamic element:
        // Level 1 => index 0, Level 2 => index 1, etc.
        var index = lv - 1;

        dynamicElements.forEach(function (el) {
          var series = el._svSeries;

          // If series is missing or not a proper list, skip it.
          if (!series || !Array.isArray(series) || series.length === 0) {
            return;
          }

          // If the series is shorter than maxLevel, clamp index to last element.
          var safeIndex = index;
          if (safeIndex >= series.length) {
            safeIndex = series.length - 1;
          }

          var value = series[safeIndex];

          // Put the chosen value into the element.
          // Use an empty string if it's null/undefined.
          if (value == null) {
            el.textContent = "";
          } else {
            el.textContent = String(value);
          }
        });
      }

      // When the slider moves, update the card live.
      slider.addEventListener("input", function () {
        applyLevel(slider.value);
      });

      // Apply the starting level right away.
      applyLevel(startLevel);

      // Mark this card as initialized so we don't do it twice.
      card.setAttribute("data-sv-init", "1");
    });
  }

  // MediaWiki hook:
  // Runs when page content is ready (and also after AJAX updates).
  if (window.mw && mw.hook) {
    mw.hook("wikipage.content").add(function ($content) {
      // $content is usually a jQuery object; $content[0] is the real DOM node.
      initSkillCards($content && $content[0]);
    });
  }

  // Also run on normal page load as a fallback.
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", function () {
      initSkillCards(document);
    });
  } else {
    initSkillCards(document);
  }

})();