MediaWiki:Common.js: Difference between revisions

Jump to navigation Jump to search
no edit summary
No edit summary
Tag: Reverted
No edit summary
Tag: Reverted
Line 1,669: Line 1,669:
   /* ---------- /Softwear PRINT ---------- */
   /* ---------- /Softwear PRINT ---------- */


   // Close modal with Close button
   /* === SW PRINT: native fallback for Entry pages === */
   $("#close-button").on("click", function () {
   (function () {
     $("#print-chooser").hide();
     // guard so we don’t double-bind if this block is included twice
     $("#show-article").removeClass("print-opts-open");
    if (window.__swPrintNativeBound) return;
     window.__swPrintNativeBound = true;


     $(".list-container").removeClass("fade-out");
     // util: create/toggle the chooser safely (no jQuery required)
    closeModal();
    function ensurePrintChooserNative() {
  });
      var chooser = document.getElementById("print-chooser");
      if (!chooser) {
        chooser = document.createElement("div");
        chooser.id = "print-chooser";
        chooser.className = "print-chooser";
        chooser.style.display = "none";
        chooser.innerHTML =
          '<a href="#" id="print-with-border" class="print-choice">border</a> ' +
          '<a href="#" id="print-no-border" class="print-choice">no border</a>';
        var printBtn = document.getElementById("print-button");
        if (printBtn && printBtn.parentNode) {
          printBtn.parentNode.insertBefore(chooser, printBtn.nextSibling);
        }
      }
      return chooser;
    }


  /* ====== SW PRINT DEBUG INSTRUMENTATION (temporary) ====== */
    function toggleChooser(show) {
  (function () {
      var chooser = ensurePrintChooserNative();
    // 1) Boot log + quick DOM probes
      var want =
    console.log("[swprint] debug wiring start");
        typeof show === "boolean" ? show : chooser.style.display === "none";
    try {
       chooser.style.display = want ? "block" : "none";
       console.log("[swprint] probes:", {
      var article = document.getElementById("show-article");
        printButton: !!document.getElementById("print-button"),
      if (article) {
        chooser: !!document.getElementById("print-chooser"),
         if (want) article.classList.add("print-opts-open");
        printOpts: !!document.getElementById("print-options"),
         else article.classList.remove("print-opts-open");
         anchorsInPage: {
       }
          with: document.querySelectorAll("#print-with-border").length,
       console.log("[swprint-native] chooser", want ? "shown" : "hidden");
          noborder: document.querySelectorAll("#print-no-border").length,
         },
        hasLocalPrintOnly: document.querySelectorAll(".print-only").length,
        hasShowArticle: !!document.getElementById("show-article"),
       });
    } catch (e) {
       console.log("[swprint] probe error:", e);
     }
     }


     // 2) Super-logger for all clicks (CAPTURE + BUBBLE)
     // MAIN: start print with pref
     function targetInfo(t) {
     function swStartPrint(borderPref) {
       if (!t) return "<none>";
       console.log("[swprint-native] start with pref:", borderPref);
      var id = t.id ? "#" + t.id : "";
 
       var cls = t.className
       try {
         ? "." + String(t.className).split(/\s+/).join(".")
         preloadFontForPrint && preloadFontForPrint();
        : "";
       } catch (e) {}
       return t.tagName + id + cls;
    }


    document.addEventListener(
      // 1) Prefer local .print-only (Entry page)
       "click",
       var local = document.querySelector(".print-only");
      function (e) {
      if (local) {
        var a = e.target.closest ? e.target.closest("a") : null;
         console.log("[swprint-native] using local .print-only");
         console.log("[swprint] CAPTURE click:", {
        toggleChooser(false);
          target: targetInfo(e.target),
        return buildIframeAndPrint(local.outerHTML, borderPref);
          closestA: a ? targetInfo(a) : "<none>",
       }
          id: e.target.id || (a && a.id) || "<none>",
          x: e.clientX,
          y: e.clientY,
        });
       },
      true
    );


    document.addEventListener(
       // 2) Otherwise fetch by title (modal / other pages)
       "click",
      var title =
      function (e) {
        window.currentEntryTitle ||
        var a = e.target.closest ? e.target.closest("a") : null;
         (window.mw &&
         console.log("[swprint] BUBBLE click:", {
           mw.config &&
           target: targetInfo(e.target),
           typeof mw.config.get === "function" &&
           closestA: a ? targetInfo(a) : "<none>",
           mw.config.get("wgPageName"));
           id: e.target.id || (a && a.id) || "<none>",
        });
      },
      false
    );


    // 3) Direct handlers for the two choices (native listeners)
      if (
    function handleChoiceClick(e) {
        !title ||
      var a = e.target.closest ? e.target.closest("a") : null;
        !(window.mw && mw.util && typeof mw.util.getUrl === "function")
       var id = (a && a.id) || e.target.id || "";
       ) {
      console.log(
        console.warn(
        "[swprint] NATIVE choice handler hit. id=",
          "[swprint-native] no title/mw.util; falling back to window.print()"
         id,
         );
         "target=",
         return window.print();
        targetInfo(e.target)
      );
      if (id !== "print-with-border" && id !== "print-no-border") {
        return; // not our link
       }
       }
       e.preventDefault();
 
       // route to the jQuery handler if present; otherwise inline minimal fallback
       var url = mw.util.getUrl(title);
      if (window.jQuery && typeof window.jQuery === "function") {
       try {
        var $ = window.jQuery;
        url = typeof cacheBust === "function" ? cacheBust(url) : url;
         var $anchor = a ? $(a) : $(e.target);
      } catch (e) {}
         if ($anchor.length) {
      console.log("[swprint-native] fetching:", url);
           console.log("[swprint] forwarding to jQuery flow…");
 
           // Simulate what your main handler expects
      fetch(url, { credentials: "same-origin" })
           try {
         .then(function (r) {
            // Trigger a jQuery click on the anchor’s exact selector (bubble path)
          return r.text();
            $anchor.trigger("click.print");
         })
           } catch (err) {
        .then(function (html) {
           var tmp = document.createElement("div");
           tmp.innerHTML = html;
           var printOnly = tmp.querySelector(".print-only");
           if (!printOnly) {
             console.warn(
             console.warn(
               "[swprint] jQuery forward failed; using inline fallback:",
               "[swprint-native] no .print-only in fetched page; window.print()"
              err
             );
             );
             inlineFallbackPrint(id);
             return window.print();
           }
           }
         } else {
          toggleChooser(false);
           inlineFallbackPrint(id);
          buildIframeAndPrint(printOnly.outerHTML, borderPref);
        })
        .catch(function (err) {
          console.warn("[swprint-native] fetch failed; window.print()", err);
          window.print();
        });
    }
 
    // helper: build iframe and call print (mirrors your jQuery version)
    function buildIframeAndPrint(printHtml, borderPref) {
      console.log("[swprint-native] buildIframeAndPrint()");
 
      var iframe = document.createElement("iframe");
      iframe.style.position = "fixed";
      iframe.style.right = "0";
      iframe.style.bottom = "0";
      iframe.style.width = "0";
      iframe.style.height = "0";
      iframe.style.border = "0";
      document.body.appendChild(iframe);
 
      var doc = iframe.contentDocument || iframe.contentWindow.document;
      doc.open();
      doc.write(
        '<!doctype html><html><head><meta charset="utf-8"><title>Print</title></head><body></body></html>'
      );
      doc.close();
 
      var base = doc.createElement("base");
      base.href = location.origin + "/";
      doc.head.appendChild(base);
 
      var cssUrl =
        "/index.php?title=MediaWiki:Print.css&action=raw&ctype=text/css";
      try {
        cssUrl = typeof cacheBust === "function" ? cacheBust(cssUrl) : cssUrl;
      } catch (e) {}
 
      var linkCss = doc.createElement("link");
      linkCss.rel = "stylesheet";
      linkCss.href = cssUrl;
      var cssLoaded = new Promise(function (res) {
        linkCss.onload = function () {
          console.log("[swprint-native] print CSS loaded");
          res();
        };
        linkCss.onerror = function () {
          console.warn("[swprint-native] print CSS failed");
          res();
         };
      });
 
      var linkFont = doc.createElement("link");
      linkFont.rel = "preload";
      linkFont.as = "font";
      linkFont.type = "font/woff2";
      linkFont.href = "/fonts/HALColant-TextRegular.woff2?v=20250820";
      linkFont.crossOrigin = "anonymous";
 
      doc.head.appendChild(linkFont);
      doc.head.appendChild(linkCss);
 
      doc.body.innerHTML = printHtml;
 
      // border pref class on <html>
      var root = doc.documentElement;
      if (borderPref === "without") root.classList.add("print-no-border");
      else root.classList.remove("print-no-border");
      console.log("[swprint-native] borderPref applied:", borderPref);
 
      // small inline tweaks (same as your version)
      var style = doc.createElement("style");
      style.textContent =
        "@media print{.article-description p,.article-reflection p,.article-external-reference p,.article-quote p{margin:0 0 1.2mm!important}.article-description p:last-child,.article-reflection p:last-child,.article-external-reference p:last-child,.article-quote p:last-child{margin-bottom:0!important}.article-entry-number,.link-pdf,.article-type,.article-metadata,.article-images,.article-description,.article-reflection,.article-external-reference,.article-quote,.article-mod-line{padding-bottom:1mm!important}[class^='article-label-']{margin-top:0!important}.article-entry-number+[class^='article-label-'],.link-pdf+[class^='article-label-'],.article-type+[class^='article-label-'],.article-metadata+[class^='article-label-'],.article-images+[class^='article-label-'],.article-description+[class^='article-label-'],.article-reflection+[class^='article-label-'],.article-external-reference+[class^='article-label-'],.article-quote+[class^='article-label-'],.article-mod-line+[class^='article-label-']{margin-top:0.9mm!important}.article-title-link{margin:0!important;padding:0!important}.article-title-link>*{margin:0!important}.link-pdf{margin-top:0!important}#article-content>:last-child{padding-bottom:0!important}#article-content>:last-child::after{content:none!important}}";
      doc.head.appendChild(style);
 
      var styleFix = doc.createElement("style");
      styleFix.textContent =
        "@media print {.article-external-reference a,.link-pdf a{white-space:nowrap!important;word-break:normal!important;overflow-wrap:normal!important;text-decoration:underline}.article-external-reference{overflow-wrap:anywhere;word-break:break-word}a[href]{position:relative}}";
      doc.head.appendChild(styleFix);
 
      // wait helpers (minimal)
      function nextFrame() {
        return new Promise(function (r) {
          (iframe.contentWindow.requestAnimationFrame || setTimeout)(r, 0);
        });
      }
      var waitFonts =
        doc.fonts && doc.fonts.ready
          ? Promise.race([
              doc.fonts.ready,
              new Promise((r) => setTimeout(r, 1200)),
            ])
          : Promise.resolve();
 
      Promise.all([cssLoaded, waitFonts, nextFrame()]).then(function () {
        console.log("[swprint-native] resources ready; print()");
        // filename by title
        var numEl = doc.querySelector(".article-entry-number");
        var entryNum = "";
        if (numEl) {
           var m = (numEl.textContent || "").match(/\d+/);
          entryNum = m ? m[0] : "";
         }
         }
       } else {
        var desiredTitle =
         inlineFallbackPrint(id);
          (entryNum ? entryNum + "." : "") + "softwear.directory";
       }
        var oldIframeTitle = doc.title;
        var oldParentTitle = document.title;
 
        iframe.contentWindow.onafterprint = function () {
          try {
            doc.title = oldIframeTitle;
            document.title = oldParentTitle;
          } catch (e) {}
          setTimeout(function () {
            if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
          }, 100);
          console.log("[swprint-native] afterprint cleanup");
        };
 
        doc.title = desiredTitle;
        document.title = desiredTitle;
 
        iframe.contentWindow.focus();
        iframe.contentWindow.print();
 
        setTimeout(function () {
          try {
            doc.title = oldIframeTitle;
            document.title = oldParentTitle;
          } catch (e) {}
          if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
          console.log("[swprint-native] timeout cleanup");
        }, 1200);
       });
    }
 
    // Bind native click to PRINT button (toggle choices)
    var printBtn = document.getElementById("print-button");
    if (printBtn) {
      printBtn.addEventListener(
         "click",
        function (e) {
          e.preventDefault();
          console.log("[swprint-native] print-button clicked");
          toggleChooser();
        },
        false
       );
     }
     }


     function inlineFallbackPrint(id) {
     // Bind native clicks to choices (border/no-border)
      console.log("[swprint] INLINE FALLBACK kick-off for", id);
    function onChoice(e) {
      // very small fallback: try to find .print-only here and window.print() it
       var a = e.target.closest && e.target.closest("a");
       var hasLocal = document.querySelector(".print-only");
       if (!a) return;
       if (!hasLocal) {
      if (a.id !== "print-with-border" && a.id !== "print-no-border") return;
        console.warn("[swprint] no .print-only on page; doing window.print()");
      e.preventDefault();
        window.print();
       var pref = a.id === "print-no-border" ? "without" : "with";
        return;
       console.log("[swprint-native] choice clicked:", pref);
       }
       swStartPrint(pref);
      console.log("[swprint] .print-only exists; asking existing code to run…");
       // Try clicking the main button again to re-enter your handler
      var btn = document.getElementById("print-button");
       if (btn) btn.click();
     }
     }


     // Attach the native handlers
     // if already present
     ["print-with-border", "print-no-border"].forEach(function (id) {
     ["print-with-border", "print-no-border"].forEach(function (id) {
       var el = document.getElementById(id);
       var el = document.getElementById(id);
       if (el) {
       if (el) el.addEventListener("click", onChoice, false);
        el.addEventListener("click", handleChoiceClick, false);
        console.log("[swprint] attached native click to", "#" + id);
      } else {
        console.log("[swprint] will delegate by document for", "#" + id);
      }
     });
     });
    // and delegate for dynamically created chooser
    document.addEventListener("click", onChoice, false);


     // Also catch via document (in case the anchors are injected later)
     console.log("[swprint-native] fallback bound");
    document.addEventListener(
  })();
      "click",
 
      function (e) {
  //ENDEND
        var a = e.target.closest
 
          ? e.target.closest("a#print-with-border, a#print-no-border")
  // Close modal with Close button
          : null;
  $("#close-button").on("click", function () {
        if (a) {
    $("#print-chooser").hide();
          handleChoiceClick(e);
    $("#show-article").removeClass("print-opts-open");
        }
      },
      false
    );


     // 4) Sanity ping after DOM mutations (some skins inject late)
     $(".list-container").removeClass("fade-out");
    setTimeout(function () {
     closeModal();
      console.log("[swprint] late check:", {
   });
        anchors: {
          with: document.querySelectorAll("#print-with-border").length,
          noborder: document.querySelectorAll("#print-no-border").length,
        },
      });
     }, 500);
   })();


  // ENDENDEND
   // Close modal and remove fade out also when clicking outside of card
   // Close modal and remove fade out also when clicking outside of card
   $(document).on("mousedown", function (event) {
   $(document).on("mousedown", function (event) {

Navigation menu