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
Tags: Reverted Mobile edit Mobile web edit
No edit summary
Tags: Reverted Mobile edit Mobile web edit
Line 1,576: Line 1,576:
(function () {
(function () {
   /* ================================================================== */
   /* ================================================================== */
   /* MODULE: Universal Popups (v2) — refined                             */
   /* MODULE: Universal Popups (v2.1) — refined                           */
   /*  - Removes redundant hint for click-open (large) popups            */
   /*  Fixes: mobile close, keyboard open, summary default toggle,        */
   /*   - Leaves hover hints optional (but CSS currently hides legacy)    */
   /*         hover enter/leave timer handling                            */
  /*  - Keeps links inside popups fully interactive (Popups friendly)  */
   /* ================================================================== */
   /* ================================================================== */


Line 1,585: Line 1,584:
   var COMMON = (SV.common = SV.common || {});
   var COMMON = (SV.common = SV.common || {});


   var POPV2_VERSION = 2; // bumped due to header/hint changes
   var POPV2_VERSION = 21; // 2.1
   if (typeof COMMON.popupsV2Init === "number" && COMMON.popupsV2Init >= POPV2_VERSION) return;
   if (typeof COMMON.popupsV2Init === "number" && COMMON.popupsV2Init >= POPV2_VERSION) return;
   COMMON.popupsV2Init = POPV2_VERSION;
   COMMON.popupsV2Init = POPV2_VERSION;
Line 1,614: Line 1,613:
     open: false,
     open: false,
     pinned: false,
     pinned: false,
     mode: "hover",     // hover | click
     mode: "hover", // hover | click
     size: "sm",         // sm | lg
     size: "sm",   // sm | lg
     trigger: null,
     trigger: null,
     lastPointerType: "mouse",
     lastPointerType: "mouse",
Line 1,639: Line 1,638:
   function safeIdSelector(id) {
   function safeIdSelector(id) {
     return "#" + String(id).replace(/([ !"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g, "\\$1");
     return "#" + String(id).replace(/([ !"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g, "\\$1");
  }
  function setHidden(el, hidden) {
    if (!el) return;
    el.setAttribute("aria-hidden", hidden ? "true" : "false");
   }
   }


Line 1,648: Line 1,652:
     el.setAttribute("role", "dialog");
     el.setAttribute("role", "dialog");
     el.setAttribute("aria-hidden", "true");
     el.setAttribute("aria-hidden", "true");
    // Keep hover popups from closing while pointer is over the popup itself
    el.addEventListener("mouseenter", function () {
      if (!HOVER_CAPABLE) return;
      if (!state.open || state.pinned) return;
      clearTimeout(state.hideTimer);
      state.hideTimer = 0;
    });
    el.addEventListener("mouseleave", function () {
      if (!HOVER_CAPABLE) return;
      if (!state.open || state.pinned) return;
      clearTimeout(state.hideTimer);
      state.hideTimer = setTimeout(function () {
        if (state.open && !state.pinned) hidePopup();
      }, 80);
    });


     document.body.appendChild(el);
     document.body.appendChild(el);
     popEl = el;
     popEl = el;
     return popEl;
     return popEl;
  }
  function setHidden(el, hidden) {
    if (!el) return;
    el.setAttribute("aria-hidden", hidden ? "true" : "false");
   }
   }


Line 1,700: Line 1,716:
     if (t == null) return "";
     if (t == null) return "";
     return String(t).trim();
     return String(t).trim();
  }
  function isSummaryTrigger(trigger) {
    return !!(trigger && trigger.tagName === "SUMMARY");
   }
   }


Line 1,763: Line 1,783:
   function guessTitle(trigger, sourceNode) {
   function guessTitle(trigger, sourceNode) {
     var pop = null;
     var pop = null;
     if (sourceNode && sourceNode.nodeType === 1) {
     if (sourceNode && sourceNode.nodeType === 1) pop = closest(sourceNode, POPUP_POP_SEL);
      pop = closest(sourceNode, POPUP_POP_SEL);
 
    }
     if (pop) {
     if (pop) {
       var t = pop.querySelector(".sv-tip-pop-title") || pop.querySelector(".sv-disclose-pop-title");
       var t = pop.querySelector(".sv-tip-pop-title") || pop.querySelector(".sv-disclose-pop-title");
Line 1,793: Line 1,812:
     else a.href = String(linkTitle);
     else a.href = String(linkTitle);


     // IMPORTANT: do not prevent default/capture on this link — Popups extension can hook it.
     // Do not prevent default/capture on this link — Popups extension can hook it.
     wrap.appendChild(a);
     wrap.appendChild(a);
     return wrap;
     return wrap;
Line 1,850: Line 1,869:
       head.addEventListener("click", function (e) {
       head.addEventListener("click", function (e) {
         e.preventDefault();
         e.preventDefault();
         hidePopup(true);
         hidePopup();
       }, { once: true });
       }, { once: true });
     }
     }
Line 1,975: Line 1,994:


     if (!attrSize) size = (mode === "click") ? "lg" : "sm";
     if (!attrSize) size = (mode === "click") ? "lg" : "sm";
    // No-hover devices: “hover” becomes tap-to-open (click-mode) so it can close properly.
    if (!HOVER_CAPABLE && mode === "hover") {
      mode = "click";
      size = (attrSize === "lg") ? "lg" : "sm";
    }


     if (isDef) {
     if (isDef) {
Line 2,019: Line 2,044:


   window.addEventListener("pointerdown", function (e) {
   window.addEventListener("pointerdown", function (e) {
     if (e && e.pointerType) state.lastPointerType = e.pointerType;
     if (!e) return;
 
    // ignore right/middle clicks
    if (typeof e.button === "number" && e.button !== 0) return;
 
    if (e.pointerType) state.lastPointerType = e.pointerType;


     // If user clicks inside popup, allow normal interactions (links, selection)
     // If user clicks inside popup, allow normal interactions (links, selection)
Line 2,029: Line 2,059:
     var opts = resolveOptsForTrigger(trigger);
     var opts = resolveOptsForTrigger(trigger);
     if (!opts) return;
     if (!opts) return;
    // Prevent native <details>/<summary> toggling whenever summary is used
    if (isSummaryTrigger(trigger)) e.preventDefault();


     // Hover-mode on mouse: don’t click-open; let hover do it
     // Hover-mode on mouse: don’t click-open; let hover do it
Line 2,040: Line 2,073:


     if (state.open && state.pinned && state.trigger === trigger) {
     if (state.open && state.pinned && state.trigger === trigger) {
       hidePopup(true);
       hidePopup();
       return;
       return;
    }
    openPopup(trigger, opts);
  }, true);
  // Keyboard open (Enter/Space) for accessibility + summary safety
  window.addEventListener("keydown", function (e) {
    if (!e) return;
    if (e.key === "Escape") {
      if (state.open) {
        hidePopup();
        e.stopPropagation();
      }
      return;
    }
    var isActivate = (e.key === "Enter" || e.key === " ");
    if (!isActivate) return;
    if (isInsidePopup(e.target)) return;
    var trigger = findTrigger(e.target);
    if (!trigger) return;
    var opts = resolveOptsForTrigger(trigger);
    if (!opts) return;
    // Keyboard activation should behave like click-open so user can read/interact
    if (opts.mode === "hover") {
      opts.mode = "click";
      opts.pinned = true;
      opts.size = "sm";
      opts.hint = "";
      opts.actionsNode = opts.actionsNode || null;
    }
    e.preventDefault();
    e.stopPropagation();
    // Stop native summary toggling as well
    if (isSummaryTrigger(trigger)) {
      try {
        var det = closest(trigger, POPUP_DETAILS_SEL);
        if (det && det.open) det.open = false;
      } catch (x) {}
     }
     }


Line 2,050: Line 2,129:
   window.addEventListener("mouseover", function (e) {
   window.addEventListener("mouseover", function (e) {
     if (!HOVER_CAPABLE) return;
     if (!HOVER_CAPABLE) return;
     if (isInsidePopup(e.target)) return; // allow moving into click popups without side effects
 
    // If entering the popup itself, keep it open
     if (isInsidePopup(e.target)) {
      if (state.open && !state.pinned) {
        clearTimeout(state.hideTimer);
        state.hideTimer = 0;
      }
      return;
    }


     var trigger = findTrigger(e.target);
     var trigger = findTrigger(e.target);
     if (!trigger) {
     if (!trigger) {
       if (state.open && !state.pinned) hidePopup(false);
       if (state.open && !state.pinned) hidePopup();
       return;
       return;
     }
     }
Line 2,080: Line 2,167:
     clearTimeout(state.hideTimer);
     clearTimeout(state.hideTimer);
     state.hideTimer = setTimeout(function () {
     state.hideTimer = setTimeout(function () {
       if (state.open && !state.pinned) hidePopup(false);
       if (state.open && !state.pinned) hidePopup();
     }, 60);
     }, 80);
   }, true);
   }, true);


   // Outside click closes pinned
   // Outside click closes (pinned always; and also closes “tap-open” popups on no-hover devices)
   window.addEventListener("click", function (e) {
   window.addEventListener("click", function (e) {
     if (!state.open) return;
     if (!state.open) return;


    // If click inside popup, do nothing (links should work; Popups can hook them)
     if (isInsidePopup(e.target)) return;
     if (isInsidePopup(e.target)) return;


    // Clicking a trigger is handled by pointerdown
     var trigger = findTrigger(e.target);
     var trigger = findTrigger(e.target);
     if (trigger) {
     if (trigger) {
Line 2,098: Line 2,183:
     }
     }


     if (state.pinned) {
     if (state.pinned || !HOVER_CAPABLE) {
      hidePopup(true);
       hidePopup();
      e.stopPropagation();
    }
  }, true);
 
  window.addEventListener("keydown", function (e) {
    if (e.key !== "Escape") return;
    if (state.open) {
       hidePopup(true);
       e.stopPropagation();
       e.stopPropagation();
     }
     }