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: Difference between revisions

MediaWiki interface page
No edit summary
No edit summary
Line 18: Line 18:
   var SERIES_SEL = "[data-series]";
   var SERIES_SEL = "[data-series]";


   // Popups (Phase 4.1 markup: span toggles + div popovers; legacy <details> supported)
   // Popups (Phase 4.1 markup: span toggles + div popovers)
  var POPUP_DETAILS_SEL = "details.sv-tip, details.sv-disclose"; // legacy
   var POPUP_WRAP_SEL = ".sv-tip, .sv-disclose";
   var POPUP_WRAP_SEL = ".sv-tip, .sv-disclose";
   var POPUP_BTN_SEL =
   var POPUP_BTN_SEL =
     ".sv-tip-btn[data-sv-toggle='1'], .sv-disclose-btn[data-sv-toggle='1']";
     ".sv-tip-btn[data-sv-toggle='1'], .sv-disclose-btn[data-sv-toggle='1']";
   var POPUP_POP_SEL = ".sv-tip-pop, .sv-disclose-pop";
   var POPUP_POP_SEL = ".sv-tip-pop, .sv-disclose-pop";
  var POPUP_HEAD_SEL = ".sv-tip-pop-head, .sv-disclose-pop-head";
   var POPUP_HIDDEN_CLASS = "sv-hidden";
   var POPUP_HIDDEN_CLASS = "sv-hidden";


Line 230: Line 230:


   /* ------------------------------------------------------------------ */
   /* ------------------------------------------------------------------ */
   /* Popup (Phase 4.1: span toggles + legacy <details> support)         */
   /* Popup (Phase 4.1: span toggles + div popovers)                     */
   /* ------------------------------------------------------------------ */
   /* ------------------------------------------------------------------ */


Line 236: Line 236:
     if (!pop) return;
     if (!pop) return;
     if (pop.classList) pop.classList.add(POPUP_HIDDEN_CLASS);
     if (pop.classList) pop.classList.add(POPUP_HIDDEN_CLASS);
    // Also set [hidden] so it hides even if CSS is missing/late.
     pop.setAttribute("hidden", "hidden");
     pop.setAttribute("hidden", "hidden");
   }
   }
Line 251: Line 250:
     if (!id) return null;
     if (!id) return null;


     // Prefer scoping to the wrapper to avoid cross-card collisions.
    var pop = document.getElementById(id);
    if (!pop) return null;
 
     // Prefer scoping to wrapper; prevents collisions if IDs ever repeat.
     var wrap = closest(btn, POPUP_WRAP_SEL);
     var wrap = closest(btn, POPUP_WRAP_SEL);
     if (wrap) {
     if (wrap && !wrap.contains(pop)) return null;
      var local = wrap.querySelector("#" + id);
      if (local) return local;
    }


     return document.getElementById(id);
     return pop;
   }
   }


Line 300: Line 299:
     }
     }
   }
   }
  /* ---------- Legacy <details> helpers (safe to keep) ---------------- */
  function closeDetails(d) {
    if (d && d.open) d.open = false;
  }
  function closeAllDetails(scope) {
    var root = scope || document;
    var openOnes = root.querySelectorAll(POPUP_DETAILS_SEL + "[open]");
    for (var i = 0; i < openOnes.length; i++) closeDetails(openOnes[i]);
  }
  /* ---------- Optional: keep aria-controls for legacy <details> ------ */
  function syncPopupAria(detailsEl) {
    var summary = detailsEl.querySelector("summary");
    if (!summary) return;
    summary.setAttribute("aria-expanded", detailsEl.open ? "true" : "false");
    var pop = detailsEl.querySelector(".sv-tip-pop, .sv-disclose-pop");
    if (pop) {
      if (!pop.id) pop.id = "svgi-pop-" + Math.random().toString(36).slice(2);
      summary.setAttribute("aria-controls", pop.id);
    }
  }
  /* ---------- Normalize popups on load ------------------------------- */


   function normalizeBtnPopups(container) {
   function normalizeBtnPopups(container) {
     var root = container || document;
     var root = container || document;


     // Ensure popup divs that carry sv-hidden are also [hidden] so they start hidden.
     // Ensure pop divs with sv-hidden are also [hidden] so they start hidden.
     var pops = root.querySelectorAll(POPUP_POP_SEL);
     var pops = root.querySelectorAll(POPUP_POP_SEL);
     for (var i = 0; i < pops.length; i++) {
     for (var i = 0; i < pops.length; i++) {
Line 354: Line 324:
   }
   }


   /* ---------- Events -------------------------------------------------- */
   // Click handling (delegated):
 
  // - clicking popup header closes
   // Click toggle (delegated)
   // - clicking toggle button toggles
  // - clicking outside any wrapper closes all
   document.addEventListener(
   document.addEventListener(
     "click",
     "click",
     function (e) {
     function (e) {
      var t = e.target;
      if (!t) return;
      // 1) Header click closes its popup
      var head = t.closest ? t.closest(POPUP_HEAD_SEL) : null;
      if (head) {
        var wrap = closest(head, POPUP_WRAP_SEL);
        if (wrap) {
          var btn = wrap.querySelector(POPUP_BTN_SEL);
          if (btn) closeBtnPopup(btn);
        }
        e.preventDefault();
        return;
      }
      // 2) Button click toggles
       var btn =
       var btn =
         e.target && e.target.closest ? e.target.closest(POPUP_BTN_SEL) : null;
         t.closest && t.closest(POPUP_BTN_SEL) ? t.closest(POPUP_BTN_SEL) : null;
       if (!btn) return;
       if (btn) {
        e.preventDefault();


      e.preventDefault();
        if (isBtnExpanded(btn)) {
          closeBtnPopup(btn);
          return;
        }


      if (isBtnExpanded(btn)) {
        closeOtherBtnPopupsWithinCard(btn);
         closeBtnPopup(btn);
         openBtnPopup(btn);
         return;
         return;
       }
       }


       closeOtherBtnPopupsWithinCard(btn);
       // 3) Click outside wrappers closes all
      openBtnPopup(btn);
      if (!closest(t, POPUP_WRAP_SEL)) {
        closeAllBtnPopups(document);
      }
     },
     },
     true
     true
   );
   );


   // Keyboard toggle (Enter/Space) (delegated)
   // Keyboard toggle (Enter/Space) + Escape closes all
   document.addEventListener(
   document.addEventListener(
     "keydown",
     "keydown",
     function (e) {
     function (e) {
      if (e.key === "Escape") {
        closeAllBtnPopups(document);
        return;
      }
       if (!(e.key === "Enter" || e.key === " " || e.key === "Spacebar"))
       if (!(e.key === "Enter" || e.key === " " || e.key === "Spacebar"))
         return;
         return;
Line 397: Line 395:
         openBtnPopup(btn);
         openBtnPopup(btn);
       }
       }
    },
    true
  );
  // Legacy <details> toggle (delegated)
  document.addEventListener(
    "toggle",
    function (e) {
      var d = e.target;
      if (!d || d.nodeType !== 1) return;
      if (!d.matches || !d.matches(POPUP_DETAILS_SEL)) return;
      // Close other legacy details within the same card.
      if (d.open) {
        var card = closest(d, CARD_SEL);
        var scope = card || document;
        var openOnes = scope.querySelectorAll(POPUP_DETAILS_SEL + "[open]");
        for (var i = 0; i < openOnes.length; i++) {
          if (openOnes[i] !== d) closeDetails(openOnes[i]);
        }
      }
      syncPopupAria(d);
    },
    true
  );
  // Click outside closes all popups
  document.addEventListener(
    "click",
    function (e) {
      var t = e.target;
      if (!t) return;
      // If click is inside any popup wrapper, do nothing.
      if (closest(t, POPUP_WRAP_SEL)) return;
      closeAllBtnPopups(document);
      closeAllDetails(document);
    },
    true
  );
  // Escape closes all popups
  document.addEventListener(
    "keydown",
    function (e) {
      if (e.key !== "Escape") return;
      closeAllBtnPopups(document);
      closeAllDetails(document);
     },
     },
     true
     true
Line 477: Line 424:
     if (!uid) {
     if (!uid) {
       _tabsUidCounter++;
       _tabsUidCounter++;
       uid = (root.getAttribute("data-tabs-root") || "svgi-tabs") + "-" + _tabsUidCounter;
       uid =
        (root.getAttribute("data-tabs-root") || "svgi-tabs") +
        "-" +
        _tabsUidCounter;
       root.setAttribute("data-tabs-uid", uid);
       root.setAttribute("data-tabs-uid", uid);
     }
     }
Line 651: Line 601:
     initLevels(root);
     initLevels(root);
     initTabs(root);
     initTabs(root);
    var container = root || document;


     // Normalize Phase 4.1 span-popups
     // Normalize Phase 4.1 span-popups
     normalizeBtnPopups(container);
     normalizeBtnPopups(root || document);
 
    // Keep legacy <details> aria in sync if any remain
    var ds = container.querySelectorAll(POPUP_DETAILS_SEL);
    for (var i = 0; i < ds.length; i++) syncPopupAria(ds[i]);
   }
   }