MediaWiki:Common.js: Difference between revisions

Jump to navigation Jump to search
no edit summary
No edit summary
No edit summary
 
(48 intermediate revisions by the same user not shown)
Line 176: Line 176:


   if ($("#home").length > 0) {
   if ($("#home").length > 0) {
    console.log("The #home element exists on this page.");
     // This code will only run only on the homepage.
     // This code will only run only on the homepage.
    // Show the block view container once everything is set up
     $(".home-block-view").show();
     $(".home-block-view").show();
     $(".home-chronicle-block-button, .home-block-view-button").addClass(
     $(".home-chronicle-block-button, .home-block-view-button").addClass(
Line 184: Line 182:
     );
     );


    // Initialization and Default Settings
     // Initially hide list view sorting buttons and set the default sorted view for block
     // Initially hide list view sorting buttons and set the default sorted view for block
     $(
     $(
Line 197: Line 194:


     $(".home-list-view-button").click(function () {
     $(".home-list-view-button").click(function () {
      console.log("List view button clicked.");
       $(".home-list-sorting-buttons").css("display", "flex");
       $(".home-list-sorting-buttons").css("display", "flex");
       // Switching view classes
       // Switching view classes
Line 882: Line 878:
   function openModal(cardElement, event) {
   function openModal(cardElement, event) {
     event.stopPropagation();
     event.stopPropagation();
    $("#print-chooser").hide();
    $("#show-article").removeClass("print-opts-open");
     var pageTitle = $(cardElement).data("page") || null; // e.g. "090"
     var pageTitle = $(cardElement).data("page") || null; // e.g. "090"
     window.currentEntryTitle = pageTitle;
     window.currentEntryTitle = pageTitle;
Line 1,223: Line 1,221:
   // closeModal function
   // closeModal function
   function closeModal() {
   function closeModal() {
    $("#print-chooser").hide();
    $("#show-article").removeClass("print-opts-open");
     if ($(".home-chronicle-list").is(":visible")) {
     if ($(".home-chronicle-list").is(":visible")) {
       $(".home-list-view").css("width", "100%");
       $(".home-list-view").css("width", "100%");
Line 1,260: Line 1,260:
   });
   });


   // --- PRINT HELPERS ---
   // HERE SHOULD BE THE NEW CODE!!!!
   // Warm the font cache in the *parent* document.
  /* ---------- Softwear PRINT (scoped, ES5-safe) ---------- */
   function preloadFontForPrint() {
 
   /* helpers */
   function swPrintPreloadFont() {
     var link = document.createElement("link");
     var link = document.createElement("link");
     link.rel = "preload";
     link.rel = "preload";
Line 1,270: Line 1,272:
     link.crossOrigin = "anonymous";
     link.crossOrigin = "anonymous";
     document.head.appendChild(link);
     document.head.appendChild(link);
    // keep it; no need to remove
   }
   }


  // Simple cache buster
   function swPrintCacheBust(url) {
   function cacheBust(url) {
     return url + (url.indexOf("?") > -1 ? "&" : "?") + "_=" + Date.now();
     return url + (url.indexOf("?") > -1 ? "&" : "?") + "_=" + Date.now();
   }
   }


   // Kill any previous print handlers
   function swEnsurePrintChooser() {
  $(document).off("click.print", "#print-button");
    var $chooser = jQuery("#print-chooser");
    if ($chooser.length) return $chooser;


  $(document).on("click.print", "#print-button", function () {
    $chooser = jQuery(
    // debounce to avoid double/racing prints
      '<div id="print-chooser" class="print-chooser" style="display:none;">' +
    var $btn = $("#print-button");
        '<a href="#" id="print-with-border" class="print-choice">show border</a> ' +
     if ($btn.data("busy")) return;
        '<a href="#" id="print-no-border" class="print-choice">hide border</a>' +
    $btn.data("busy", true);
        "</div>"
    );
     jQuery("#print-button").after($chooser);


     preloadFontForPrint();
     // Bind once on the chooser to catch nested elements
 
    if (!$chooser.data("swBound")) {
    var title = window.currentEntryTitle; // e.g. "090"
      function chooserFire(ev, where) {
    if (!title) {
        ev = ev || window.event;
      console.warn("[print] no currentEntryTitle");
        var t = ev && (ev.target || ev.srcElement);
       window.print();
        var a = t && t.closest ? t.closest("a[id]") : null;
       $btn.data("busy", false);
        if (!a) return;
       return;
        var id = a.getAttribute("id");
        if (id !== "print-with-border" && id !== "print-no-border") return;
        if (ev.preventDefault) ev.preventDefault();
        if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();
        if (ev.stopPropagation) ev.stopPropagation();
        swHandlePrintChoice(id, (window.jQuery && jQuery(a)) || null);
        return false;
      }
       $chooser.on("pointerdown", chooserFire);
      $chooser.on("touchstart", chooserFire);
      $chooser.on("mousedown", chooserFire);
       $chooser.on("click", chooserFire);
       $chooser.data("swBound", true);
     }
     }
    return $chooser;
  }


     var pageUrl = mw.util.getUrl(title);
  function swHidePrintUI() {
     var pageUrlFresh = cacheBust(pageUrl);
     jQuery("#print-chooser").hide();
    console.log("[print] fetching page HTML:", pageUrlFresh);
     jQuery("#show-article").removeClass("print-opts-open");
  }


    $.get(pageUrlFresh)
  /* small boot probe */
       .done(function (html) {
  (function () {
         var $tmp = $("<div>").html(html);
    try {
         var $print = $tmp.find(".print-only").first();
       console.log("[swprint] probe on load", {
         console.log("[print] .print-only found:", $print.length);
         printButton: !!document.getElementById("print-button"),
 
         chooserExists: !!document.getElementById("print-chooser"),
         if (!$print.length) {
         localPrintOnlyCount: jQuery(".print-only").length,
          console.warn("[print] no .print-only found; fallback print");
         showArticleExists: !!document.getElementById("show-article"),
          window.print();
      });
          $btn.data("busy", false);
    } catch (e) {}
          return;
  })();
        }


        // Build hidden iframe
  /* core: build iframe and print */
        var iframe = document.createElement("iframe");
  function swBuildIframeAndPrint(printHtml, borderPref, $btn) {
        iframe.style.position = "fixed";
    // iframe
        iframe.style.right = "0";
    var iframe = document.createElement("iframe");
        iframe.style.bottom = "0";
    iframe.style.position = "fixed";
        iframe.style.width = "0";
    iframe.style.right = "0";
        iframe.style.height = "0";
    iframe.style.bottom = "0";
        iframe.style.border = "0";
    iframe.style.width = "0";
        document.body.appendChild(iframe);
    iframe.style.height = "0";
    iframe.style.border = "0";
    document.body.appendChild(iframe);


        var doc = iframe.contentDocument || iframe.contentWindow.document;
    var doc = iframe.contentDocument || iframe.contentWindow.document;
        doc.open();
    doc.open();
        doc.write(
    doc.write(
          '<!doctype html><html><head><meta charset="utf-8"><title>Print</title></head><body></body></html>'
      '<!doctype html><html><head><meta charset="utf-8"><title>Print</title></head><body></body></html>'
        );
    );
        doc.close();
    doc.close();


        // Ensure relative URLs (fonts/images) resolve inside iframe
    // make relative URLs resolve
        var base = doc.createElement("base");
    var base = doc.createElement("base");
        base.href = location.origin + "/";
    base.href = location.origin + "/";
        doc.head.appendChild(base);
    doc.head.appendChild(base);


        // Inject PRINT CSS (cache-busted) and await it
    // print.css
        var printCssUrl =
    var linkCss = doc.createElement("link");
          "/index.php?title=MediaWiki:Print.css&action=raw&ctype=text/css";
    linkCss.rel = "stylesheet";
        var printCssFresh = cacheBust(printCssUrl);
    linkCss.href = swPrintCacheBust(
      "/index.php?title=MediaWiki:Print.css&action=raw&ctype=text/css"
    );


        var linkCss = doc.createElement("link");
    var cssLoaded = new Promise(function (resolve) {
        linkCss.rel = "stylesheet";
      linkCss.onload = resolve;
        linkCss.href = printCssFresh;
      linkCss.onerror = resolve;
 
    });
        var cssLoaded = new Promise(function (resolve) {
          linkCss.onload = function () {
            resolve();
          };
          linkCss.onerror = function () {
            console.warn("[print] CSS failed to load");
            resolve();
          }; // don't block
        });


        // Preload the font *inside* iframe (Chrome becomes much happier)
    // font preload (inside iframe)
        var linkFont = doc.createElement("link");
    var linkFont = doc.createElement("link");
        linkFont.rel = "preload";
    linkFont.rel = "preload";
        linkFont.as = "font";
    linkFont.as = "font";
        linkFont.type = "font/woff2";
    linkFont.type = "font/woff2";
        linkFont.href = "/fonts/HALColant-TextRegular.woff2?v=20250820";
    linkFont.href = "/fonts/HALColant-TextRegular.woff2?v=20250820";
        linkFont.crossOrigin = "anonymous";
    linkFont.crossOrigin = "anonymous";


        doc.head.appendChild(linkFont);
    doc.head.appendChild(linkFont);
        doc.head.appendChild(linkCss);
    doc.head.appendChild(linkCss);


        // Inject the printable HTML
    // inject HTML
        doc.body.innerHTML = $print.prop("outerHTML");
    doc.body.innerHTML = printHtml;


        // Remove “empty” optional sections so they don’t leave gaps in print.
    // sanitize: remove inner .print-no-border if user chose WITH border
        // Kill UA paragraph margins & set compact rhythm (ES5-safe)
    (function () {
        var compactCSS = doc.createElement("style");
      var stray = doc.querySelectorAll(".print-no-border");
        compactCSS.type = "text/css";
      if (borderPref === "with" && stray.length) {
        compactCSS.appendChild(
        Array.prototype.forEach.call(stray, function (el) {
          doc.createTextNode(
          el.className = (el.className || "")
            "@media print {" +
            .replace(/\bprint-no-border\b/g, "")
              "  .print-only p { margin:0 !important; }" +
            .trim();
              "  #article-content > * { margin-top:0 !important; margin-bottom:0 !important; }" +
        });
              "  #article-content > * + * { margin-top:2mm !important; }" +
      }
              "  .article-description p," +
    })();
              " .article-reflection p," +
              "  .article-external-reference p," +
              "  .article-quote { margin:0 0 1.2mm 0 !important; }" +
              "  .article-description p:last-child," +
              "  .article-reflection p:last-child," +
              "  .article-external-reference p:last-child { margin-bottom:0 !important; }" +
              "  .article-label-description," +
              "  .article-label-reflection," +
              "  .article-label-external-reference," +
              "  .article-label-quote," +
              "  .article-label-modification-date { margin: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 { margin:0 !important; }" +
              "}"
          )
        );
        doc.head.appendChild(compactCSS);


        // --- PDF-friendly links for Chrome on macOS ---
    // apply border preference to <html>
        // 1) Add a tiny print-only CSS override to keep anchors as one box.
    (function () {
        var linkCssFix = doc.createElement("style");
      var htmlEl = doc.documentElement;
         linkCssFix.textContent =
      if (borderPref === "without") {
          "@media print {\n" +
         if (htmlEl.classList) htmlEl.classList.add("print-no-border");
          "  /* Keep anchor boxes intact so Chrome preserves the PDF annotation */\n" +
        else if (
           " .article-external-reference a,\n" +
           (" " + htmlEl.className + " ").indexOf(" print-no-border ") === -1
          "  .link-pdf a {\n" +
        ) {
          "   white-space: nowrap !important;\n" +
           htmlEl.className += " print-no-border";
          "   word-break: normal !important;\n" +
        }
          "    overflow-wrap: normal !important;\n" +
      } else {
          "    text-decoration: underline;\n" +
         if (htmlEl.classList) htmlEl.classList.remove("print-no-border");
          "  }\n" +
        else
           "  /* Allow wrapping outside the anchor instead */\n" +
          htmlEl.className = (htmlEl.className || "").replace(
          " .article-external-reference {\n" +
            /\bprint-no-border\b/g,
          "    overflow-wrap: anywhere;\n" +
             ""
          "    word-break: break-word;\n" +
          "  }\n" +
          "  /* Defensive: make sure anchors have a box */\n" +
          "  a[href] { position: relative; }\n" +
          "}\n";
         doc.head.appendChild(linkCssFix);
 
        // 2) Normalize long link text so it doesn't force wrapping inside anchors.
        (function () {
          // Shorten long visible URLs in external references, keep href intact
          var refs = doc.querySelectorAll(
             ".article-external-reference a[href]"
           );
           );
          refs.forEach(function (a) {
      }
            var txt = (a.textContent || "").trim();
    })();
            var href = a.getAttribute("href") || "";
            var looksLongUrl = /^https?:\/\//i.test(txt) && txt.length > 60;


            if (looksLongUrl) {
    // OPTIONAL: glue label + body together (extra safety vs. page breaks)
              try {
    (function () {
                var u = new URL(href, doc.baseURI);
      var style = doc.createElement("style");
                var label =
      style.textContent =
                  u.hostname +
        "@media print{.sw-keep{break-inside:avoid;page-break-inside:avoid;}}";
                  (u.pathname.replace(/\/$/, "") ? u.pathname : "");
      doc.head.appendChild(style);
                if (label.length > 40) label = label.slice(0, 37) + "…";
                a.textContent = label;
              } catch (e) {
                a.textContent = "Link";
              }
            }


            // Ensure single-box anchors
      var pairs = [
            a.style.whiteSpace = "nowrap";
        [".article-label-description", ".article-description"],
            a.style.wordBreak = "normal";
        [".article-label-reflection", ".article-reflection"],
            a.style.overflowWrap = "normal";
        [".article-label-external-reference", ".article-external-reference"],
          });
        [".article-label-quote", ".article-quote"],
        [".article-label-modification-date", ".article-modification-date"],
      ];


          // Icon links ([PDF⤴] [WEB⤴]) are short; still enforce single-box
      for (var i = 0; i < pairs.length; i++) {
          doc.querySelectorAll(".link-pdf a[href]").forEach(function (a) {
        var labelSel = pairs[i][0];
            a.style.whiteSpace = "nowrap";
        var bodySel = pairs[i][1];
            a.style.wordBreak = "normal";
        var labels = doc.querySelectorAll(labelSel);
            a.style.overflowWrap = "normal";
        for (var j = 0; j < labels.length; j++) {
           });
          var label = labels[j];
         })();
          var body = label.nextElementSibling;
          if (!body || !body.matches(bodySel)) continue;
          var wrap = doc.createElement("div");
          wrap.className = "sw-keep";
          label.parentNode.insertBefore(wrap, label);
          wrap.appendChild(label);
           wrap.appendChild(body);
         }
      }
    })();


        // Wait helpers
    // clean empty paragraphs
        function waitImages() {
    (function () {
          var imgs = [].slice.call(doc.images || []);
      var ps = doc.querySelectorAll("#article-content p");
           if (!imgs.length) return Promise.resolve();
      Array.prototype.forEach.call(ps, function (p) {
           return Promise.all(
        var txt = (p.textContent || "").replace(/\u00a0/g, " ").trim();
            imgs.map(function (img) {
        var onlyBr =
              if (img.decode) {
           p.children &&
                try {
          p.children.length === 1 &&
                  return img.decode().catch(function () {});
          p.firstElementChild &&
                } catch (e) {}
           p.firstElementChild.tagName === "BR";
              }
        if (
              return new Promise(function (res) {
          (!txt && !p.querySelector("img, a, strong, em, span:not(:empty)")) ||
                if (img.complete) return res();
          onlyBr
                img.onload = img.onerror = function () {
        ) {
                  res();
          if (p.parentNode) p.parentNode.removeChild(p);
                };
        }
              });
      });
            })
      var root = doc.getElementById("article-content");
          );
      if (root) {
        var kids = Array.prototype.slice.call(root.childNodes);
        for (var k = 0; k < kids.length; k++) {
          var n = kids[k];
          if (n.nodeType === 3 && !n.textContent.replace(/\s+/g, "")) {
            root.removeChild(n);
          }
         }
         }
      }
    })();
    // inline micro-tweaks for print spacing
    (function () {
      var css =
        "@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;}" +
        "  .article-label-description + .article-description," +
        "  .article-label-reflection + .article-reflection," +
        "  .article-label-external-reference + .article-external-reference," +
        "  .article-label-quote + .article-quote," +
        "  .article-label-modification-date + .article-modification-date{margin-top:0!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;}" +
        "}";
      var style = doc.createElement("style");
      style.type = "text/css";
      style.appendChild(doc.createTextNode(css));
      doc.head.appendChild(style);
    })();


        function waitFonts(timeoutMs) {
    // link tweaks (wrapping / underline)
          if (!doc.fonts || !doc.fonts.ready) return Promise.resolve();
    (function () {
          var ready = doc.fonts.ready;
      var styleFix = doc.createElement("style");
          var t = new Promise(function (res) {
      styleFix.textContent =
            setTimeout(res, timeoutMs || 1200);
        "@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);
          return Promise.race([ready, t]);
        }


        // **Load the specific face** so Chrome actually uses it
      var refs = doc.querySelectorAll(".article-external-reference a[href]");
        function waitSpecificFont(timeoutMs) {
      Array.prototype.forEach.call(refs, function (a) {
          if (!doc.fonts || !doc.fonts.load) return Promise.resolve();
        var txt = (a.textContent || "").trim();
          var p = Promise.all([
        var href = a.getAttribute("href") || "";
            doc.fonts.load('400 16px "HALColant-TextRegular"'),
        var looksLongUrl = /^https?:\/\//i.test(txt) && txt.length > 60;
            doc.fonts.load('normal 16px "HALColant-TextRegular"'),
        if (looksLongUrl) {
           ]);
           try {
          var t = new Promise(function (res) {
            var u = new URL(href, doc.baseURI);
             setTimeout(res, timeoutMs || 1200);
            var label =
           });
              u.hostname + (u.pathname.replace(/\/$/, "") ? u.pathname : "");
           return Promise.race([p, t]);
             if (label.length > 40) label = label.slice(0, 37) + "…";
            a.textContent = label;
           } catch (e) {
            a.textContent = "Link";
           }
         }
         }
        a.style.whiteSpace = "nowrap";
        a.style.wordBreak = "normal";
        a.style.overflowWrap = "normal";
      });
    })();


         function nextFrame() {
    // waits
    function waitImages() {
      var imgs = [].slice.call(doc.images || []);
      if (!imgs.length) return Promise.resolve();
      return Promise.all(
         imgs.map(function (img) {
          if (img.decode) {
            try {
              return img.decode().catch(function () {});
            } catch (e) {}
          }
           return new Promise(function (res) {
           return new Promise(function (res) {
             (iframe.contentWindow.requestAnimationFrame || setTimeout)(res, 0);
             if (img.complete) return res();
            img.onload = img.onerror = function () {
              res();
            };
           });
           });
        })
      );
    }
    function waitFonts(timeoutMs) {
      if (!doc.fonts || !doc.fonts.ready) return Promise.resolve();
      var ready = doc.fonts.ready;
      var t = new Promise(function (res) {
        setTimeout(res, timeoutMs || 1200);
      });
      return Promise.race([ready, t]);
    }
    function waitSpecificFont(timeoutMs) {
      if (!doc.fonts || !doc.fonts.load) return Promise.resolve();
      var p = Promise.all([
        doc.fonts.load('400 16px "HALColant-TextRegular"'),
        doc.fonts.load('normal 16px "HALColant-TextRegular"'),
      ]);
      var t = new Promise(function (res) {
        setTimeout(res, timeoutMs || 1200);
      });
      return Promise.race([p, t]);
    }
    function nextFrame() {
      return new Promise(function (res) {
        (iframe.contentWindow.requestAnimationFrame || setTimeout)(res, 0);
      });
    }
    Promise.all([
      cssLoaded,
      waitImages(),
      waitFonts(1200),
      waitSpecificFont(1200),
      nextFrame(),
    ])
      .then(function () {
        // filename via document.title
        var entryNum = "";
        var numEl = doc.querySelector(".article-entry-number");
        if (numEl) {
          var m = (numEl.textContent || "").match(/\d+/);
          entryNum = m ? m[0] : "";
         }
         }
        var desiredTitle =
          (entryNum ? entryNum + "." : "") + "softwear.directory";
        var oldIframeTitle = doc.title;
        var oldParentTitle = document.title;


        // Extra cleanup guard (Chrome sometimes delays afterprint)
         iframe.contentWindow.onafterprint = function () {
         iframe.contentWindow.onafterprint = function () {
          try {
            doc.title = oldIframeTitle;
            document.title = oldParentTitle;
          } catch (e) {}
           setTimeout(function () {
           setTimeout(function () {
             if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
             if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
           }, 100);
           }, 100);
           $btn.data("busy", false);
           if ($btn && $btn.length) $btn.data("busy", false);
         };
         };


         Promise.all([
         doc.title = desiredTitle;
          cssLoaded,
        document.title = desiredTitle;
          waitImages(),
 
          waitFonts(1200),
        iframe.contentWindow.focus();
          waitSpecificFont(1200),
        iframe.contentWindow.print();
          nextFrame(), // settle layout
 
         ]).then(function () {
        // safety cleanup
         setTimeout(function () {
           try {
           try {
             iframe.contentWindow.focus();
             doc.title = oldIframeTitle;
            iframe.contentWindow.print();
            document.title = oldParentTitle;
          } finally {
          } catch (e) {}
            // fallback cleanup in case onafterprint doesn't fire
          if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
            setTimeout(function () {
          if ($btn && $btn.length) $btn.data("busy", false);
              if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
        }, 1000);
              $btn.data("busy", false);
      })
            }, 1000);
      .catch(function () {
           }
        if ($btn && $btn.length) $btn.data("busy", false);
         });
      });
  }
 
  /* decide source & kick print */
  function swHandlePrintChoice(id, $btn) {
    if ($btn && $btn.data("busy")) return;
    if ($btn && $btn.length) $btn.data("busy", true);
 
    var borderPref = id === "print-no-border" ? "without" : "with";
    swPrintPreloadFont();
 
    // prefer local .print-only (Entry page)
    var localPrintOnly = jQuery(".print-only").first();
    if (localPrintOnly.length) {
      swHidePrintUI();
      swBuildIframeAndPrint(localPrintOnly.prop("outerHTML"), borderPref, $btn);
      return;
    }
 
    // otherwise fetch by title (modal/home)
    var title =
      window.currentEntryTitle ||
      (window.mw && mw.config && mw.config.get && mw.config.get("wgPageName"));
    if (!title) {
      window.print();
      if ($btn && $btn.length) $btn.data("busy", false);
      return;
    }
 
    var pageUrl =
      window.mw && mw.util && mw.util.getUrl
        ? mw.util.getUrl(title)
        : "/wiki/" + String(title);
 
    jQuery
      .get(swPrintCacheBust(pageUrl))
      .done(function (html) {
        var $tmp = jQuery("<div>").html(html);
        var $print = $tmp.find(".print-only").first();
        if (!$print.length) {
          window.print();
          if ($btn && $btn.length) $btn.data("busy", false);
           return;
        }
         swHidePrintUI();
        swBuildIframeAndPrint($print.prop("outerHTML"), borderPref, $btn);
       })
       })
       .fail(function (xhr) {
       .fail(function () {
        console.warn(
          "[print] fetch failed:",
          xhr && xhr.status,
          xhr && xhr.statusText
        );
         window.print();
         window.print();
         $("#print-button").data("busy", false);
         jQuery("#print-button").data("busy", false);
       });
       });
  }
  /* bind current choice anchors (defensive, for Entry pages) */
  function swBindChoiceAnchors() {
    var sel = "#print-with-border, #print-no-border";
    var els = document.querySelectorAll(sel);
    for (var i = 0; i < els.length; i++) {
      (function (el) {
        if (el.__swChoiceBound) return;
        el.__swChoiceBound = true;
        // ensure clickable/accessible
        try {
          el.style.pointerEvents = el.style.pointerEvents || "auto";
          if (!el.getAttribute("role")) el.setAttribute("role", "button");
          if (!el.getAttribute("tabindex")) el.setAttribute("tabindex", "0");
        } catch (e) {}
        function fire(ev) {
          if (ev && ev.preventDefault) ev.preventDefault();
          if (ev && ev.stopImmediatePropagation) ev.stopImmediatePropagation();
          if (ev && ev.stopPropagation) ev.stopPropagation();
          var $a = (window.jQuery && jQuery(el)) || null;
          swHandlePrintChoice(el.id, $a);
          return false;
        }
        // early + normal phases
        el.addEventListener("pointerdown", fire, true);
        el.addEventListener("touchstart", fire, true);
        el.addEventListener("mousedown", fire, true);
        el.addEventListener("click", fire, true);
        el.addEventListener("click", fire, false);
        if (!el.onclick) el.onclick = fire;
        // keyboard
        el.addEventListener(
          "keydown",
          function (e) {
            var k = e.key || e.keyCode;
            if (k === "Enter" || k === 13 || k === " " || k === 32) fire(e);
          },
          true
        );
      })(els[i]);
    }
  }
  /* early global catcher (minimal) */
  (function () {
    if (window.__swprintEarlyCatcher) return;
    window.__swprintEarlyCatcher = true;
    function routeEarly(ev) {
      var t = ev.target;
      if (!t || !t.closest) return;
      var a = t.closest("a#print-with-border, a#print-no-border");
      if (!a) return;
      if (ev.preventDefault) ev.preventDefault();
      if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();
      if (ev.stopPropagation) ev.stopPropagation();
      swHandlePrintChoice(a.id, (window.jQuery && jQuery(a)) || null);
      return false;
    }
    window.addEventListener("pointerdown", routeEarly, true);
    window.addEventListener("touchstart", routeEarly, true);
    window.addEventListener("mousedown", routeEarly, true);
  })();
  /* wiring (namespaced) */
  jQuery(document).off("click.swprint");
  jQuery(document).on(
    "click.swprint",
    "#print-button, #print-chooser, #print-options",
    function (e) {
      // main [print] toggler
      if (jQuery(e.target).closest("#print-button").length) {
        e.preventDefault();
        var $chooser = swEnsurePrintChooser();
        $chooser.css({ position: "absolute", zIndex: 99999 });
        $chooser.toggle();
        var visible = $chooser.is(":visible");
        jQuery("#show-article").toggleClass("print-opts-open", visible);
        // ensure anchors are bound (important on Entry pages)
        swBindChoiceAnchors();
        return;
      }
      // click directly on a choice link (fallback path)
      var $choice = jQuery(e.target).closest(
        "a#print-with-border, a#print-no-border"
      );
      if (!$choice.length) return;
      e.preventDefault();
      swHandlePrintChoice($choice.attr("id"), $choice);
    }
  );
  // map any <button> inside chooser to its host anchor
  jQuery(document).on(
    "click.swprintChoiceBtn2",
    "#print-chooser button",
    function (e) {
      var host = this.closest(
        '[id="print-with-border"], [id="print-no-border"]'
      );
      if (!host) return;
      e.preventDefault();
      swHandlePrintChoice(host.id, (window.jQuery && jQuery(host)) || null);
    }
  );
  // hide choices on ESC
  jQuery(document).on("keydown.swprint", function (e) {
    if (e && e.keyCode === 27) swHidePrintUI();
   });
   });
  /* ---------- /Softwear PRINT ---------- */


   // Close modal with Close button
   // Close modal with Close button
   $("#close-button").on("click", function () {
   $("#close-button").on("click", function () {
    $("#print-chooser").hide();
    $("#show-article").removeClass("print-opts-open");
     $(".list-container").removeClass("fade-out");
     $(".list-container").removeClass("fade-out");
     closeModal();
     closeModal();
Line 1,614: Line 1,856:
   }
   }


   // NRS ENTRIES  ---------------------  SECTION //
   // paragraph-formatting block
  console.log("Document ready!"); // Check if document ready event is triggered
   if (jQuery("#show-article-wrapper-entry").length) {
 
   if ($("#show-article-wrapper-entry").length) {
    console.log("Element with id 'show-article-wrapper-entry' found!"); // Check if the target element exists
 
    // Your existing formatParagraphs function
     function formatParagraphs(text) {
     function formatParagraphs(text) {
       var paragraphs = text.split("\n").filter(function (p) {
      // split on newlines, drop empty lines, wrap each in <p>
         return p.trim() !== "";
       var parts = String(text || "").split("\n");
      });
      var out = [];
      return paragraphs
      for (var i = 0; i < parts.length; i++) {
         .map(function (p) {
         var p = parts[i].replace(/^\s+|\s+$/g, "");
          return "<p>" + p.trim() + "</p>";
         if (p) out.push("<p>" + p + "</p>");
        })
      }
        .join("");
      return out.join("");
     }
     }


     // Check if ".article-description" exists and format its text
     jQuery(
    if ($(".article-description").length) {
      "#show-article .article-description, #show-article .article-reflection"
       var descriptionText = $(".article-description").text();
    ).each(function () {
       var formattedDescription = formatParagraphs(descriptionText);
       var $el = jQuery(this);
      $(".article-description").html(formattedDescription); // Set the formatted text
       if ($el.children("p").length > 0) return; // already formatted by PageForms
    }
       var rawText = $el.text();
 
       $el.html(formatParagraphs(rawText));
    // Check if ".article-reflection" exists and format its text
     });
    if ($(".article-reflection").length) {
       var reflectionText = $(".article-reflection").text();
      var formattedReflection = formatParagraphs(reflectionText);
       $(".article-reflection").html(formattedReflection); // Set the formatted text
     }
   }
   }


Line 1,707: Line 1,939:
   // Check if #submit button exists and add event listener if it does
   // Check if #submit button exists and add event listener if it does
   var submitButton = document.querySelector("#submit");
   var submitButton = document.querySelector("#submit");
  console.log("Submit button:", submitButton);


   if (submitButton) {
   if (submitButton) {
    console.log("#submit button found.");
     // Add click event listener
     // Add click event listener
     submitButton.addEventListener("click", function (event) {
     submitButton.addEventListener("click", function (event) {
      console.log("Submit button clicked.");
       event.preventDefault(); // Prevent the default link behavior
       event.preventDefault(); // Prevent the default link behavior


Navigation menu