MediaWiki:Common.js: Difference between revisions

Jump to navigation Jump to search
no edit summary
No edit summary
No edit summary
Line 1,282: Line 1,282:
     if ($chooser.length) return $chooser;
     if ($chooser.length) return $chooser;


    // Keep your existing IDs (print-with-border / print-no-border)
     $chooser = jQuery(
     $chooser = jQuery(
       '<div id="print-chooser" class="print-chooser" style="display:none;">' +
       '<div id="print-chooser" class="print-chooser" style="display:none;">' +
Line 1,291: Line 1,290:
     jQuery("#print-button").after($chooser);
     jQuery("#print-button").after($chooser);


     // Bind ONCE, on the chooser itself (robust to nested elements)
     // Bind once on the chooser to catch nested elements
     if (!$chooser.data("swBound")) {
     if (!$chooser.data("swBound")) {
       function chooserFire(ev, where) {
       function chooserFire(ev, where) {
         var a =
        ev = ev || window.event;
          ev.target && ev.target.closest ? ev.target.closest("a[id]") : null;
         var t = ev && (ev.target || ev.srcElement);
        var a = t && t.closest ? t.closest("a[id]") : null;
         if (!a) return;
         if (!a) return;
         var id = a.getAttribute("id");
         var id = a.getAttribute("id");
         if (id !== "print-with-border" && id !== "print-no-border") return;
         if (id !== "print-with-border" && id !== "print-no-border") return;
         try {
         if (ev.preventDefault) ev.preventDefault();
          console.log("[swprint] chooser " + where + " ->", id);
         if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();
        } catch (e2) {}
         if (ev.stopPropagation) ev.stopPropagation();
        ev.preventDefault && ev.preventDefault();
         swHandlePrintChoice(id, (window.jQuery && jQuery(a)) || null);
         ev.stopImmediatePropagation && ev.stopImmediatePropagation();
         ev.stopPropagation && ev.stopPropagation();
         swHandlePrintChoice(id, jQuery(a));
         return false;
         return false;
       }
       }
       $chooser.on(
       $chooser.on("pointerdown", chooserFire);
        "pointerdown",
       $chooser.on("touchstart", chooserFire);
        chooserFire.bind(null, /*ev*/ null, "pointerdown")
       $chooser.on("mousedown", chooserFire);
      ); // jQuery will pass ev
       $chooser.on("click", chooserFire);
       $chooser.on("touchstart", chooserFire.bind(null, null, "touchstart"));
       $chooser.on("mousedown", chooserFire.bind(null, null, "mousedown"));
       $chooser.on("click", chooserFire.bind(null, null, "click"));
 
       $chooser.data("swBound", true);
       $chooser.data("swBound", true);
      try {
        console.log("[swprint] chooser handler bound");
      } catch (e) {}
     }
     }
     return $chooser;
     return $chooser;
   }
   }
Line 1,330: Line 1,319:
   }
   }


  /* small boot probe */
   (function () {
   (function () {
     try {
     try {
Line 1,340: Line 1,330:
     } catch (e) {}
     } catch (e) {}
   })();
   })();
  try {
    swBindChoiceAnchors();
  } catch (e) {}


   /* core: build iframe and print */
   /* core: build iframe and print */
   function swBuildIframeAndPrint(printHtml, borderPref, $btn) {
   function swBuildIframeAndPrint(printHtml, borderPref, $btn) {
    console.log("[swprint] buildIframeAndPrint()", {
      borderPref: borderPref,
      htmlLen: printHtml ? printHtml.length : 0,
    });
     // iframe
     // iframe
     var iframe = document.createElement("iframe");
     var iframe = document.createElement("iframe");
Line 1,381: Line 1,363:


     var cssLoaded = new Promise(function (resolve) {
     var cssLoaded = new Promise(function (resolve) {
       linkCss.onload = function () {
       linkCss.onload = resolve;
        resolve();
       linkCss.onerror = resolve;
      };
       linkCss.onerror = function () {
        resolve();
      };
     });
     });


Line 1,403: Line 1,381:
     doc.body.innerHTML = printHtml;
     doc.body.innerHTML = printHtml;


     // --- sanitize: kill any inner .print-no-border (when user chose WITH border) ---
     // sanitize: remove inner .print-no-border if user chose WITH border
     (function () {
     (function () {
       var stray = doc.querySelectorAll(".print-no-border");
       var stray = doc.querySelectorAll(".print-no-border");
       if (borderPref === "with" && stray.length) {
       if (borderPref === "with" && stray.length) {
         Array.prototype.forEach.call(stray, function (el) {
         Array.prototype.forEach.call(stray, function (el) {
           el.className = el.className
           el.className = (el.className || "")
             .replace(/\bprint-no-border\b/g, "")
             .replace(/\bprint-no-border\b/g, "")
             .trim();
             .trim();
Line 1,415: Line 1,393:
     })();
     })();


    // apply border preference to <html>
     (function () {
     (function () {
       var htmlEl = doc.documentElement;
       var htmlEl = doc.documentElement;
Line 1,427: Line 1,406:
         if (htmlEl.classList) htmlEl.classList.remove("print-no-border");
         if (htmlEl.classList) htmlEl.classList.remove("print-no-border");
         else
         else
           htmlEl.className = htmlEl.className.replace(
           htmlEl.className = (htmlEl.className || "").replace(
             /\bprint-no-border\b/g,
             /\bprint-no-border\b/g,
             ""
             ""
           );
           );
       }
       }
      console.log(
        "[swprint] html class after apply:",
        htmlEl.className || "<empty>"
      );
     })();
     })();


     // Enforce via CSS (covers cases where wrapper class differs)
     // OPTIONAL: glue label + body together (extra safety vs. page breaks)
     (function () {
     (function () {
      var css =
        borderPref === "without"
          ? "@media print{.entry-wrapper,.entry-wrapper.print-a4-narrow{border:0!important;box-shadow:none!important;}}"
          : "@media print{.entry-wrapper,.entry-wrapper.print-a4-narrow{border:1px solid #000!important;}}";
       var style = doc.createElement("style");
       var style = doc.createElement("style");
       style.appendChild(doc.createTextNode(css));
       style.textContent =
        "@media print{.sw-keep{break-inside:avoid;page-break-inside:avoid;}}";
       doc.head.appendChild(style);
       doc.head.appendChild(style);
      console.log("[swprint] CSS enforcement injected for:", borderPref);
    })();


    // FINAL INLINE FALLBACK: force the visible wrapper’s border directly
       var pairs = [
    (function () {
         [".article-label-description", ".article-description"],
      // try common wrappers; fall back to first element in body
         [".article-label-reflection", ".article-reflection"],
       var wrapper =
        [".article-label-external-reference", ".article-external-reference"],
         doc.querySelector(".entry-wrapper") ||
        [".article-label-quote", ".article-quote"],
         doc.querySelector(".print-a4-narrow") ||
         [".article-label-modification-date", ".article-modification-date"],
         doc.body.firstElementChild;
      ];


       if (!wrapper) {
       for (var i = 0; i < pairs.length; i++) {
         console.warn("[swprint] no wrapper found for inline border fallback");
         var labelSel = pairs[i][0];
         return;
         var bodySel = pairs[i][1];
      }
        var labels = doc.querySelectorAll(labelSel);
 
        for (var j = 0; j < labels.length; j++) {
      var old = wrapper.getAttribute("style") || "";
          var label = labels[j];
      var force =
          var body = label.nextElementSibling;
        borderPref === "without"
          if (!body || !body.matches(bodySel)) continue;
          ? "border:0!important;"
          var wrap = doc.createElement("div");
          : "border:1px solid #000!important;";
          wrap.className = "sw-keep";
 
          label.parentNode.insertBefore(wrap, label);
      wrapper.setAttribute("style", force + old);
           wrap.appendChild(label);
      console.log(
           wrap.appendChild(body);
        "[swprint] inline border fallback applied on:",
         }
        wrapper.className || wrapper.tagName,
        "pref:",
        borderPref
      );
    })();
 
    // DIAG 1: dump computed border style on the chosen wrapper
    (function () {
      var wrapper =
        doc.querySelector(".entry-wrapper") ||
        doc.querySelector(".print-a4-narrow") ||
        doc.body.firstElementChild;
      if (!wrapper) return;
      var cs = doc.defaultView.getComputedStyle(wrapper);
      console.log(
        "[swprint] computed border:",
        cs.borderTopWidth,
        cs.borderTopStyle,
        cs.borderTopColor,
        "|",
        cs.borderRightWidth,
        cs.borderRightStyle,
        cs.borderRightColor,
        "|",
        cs.borderBottomWidth,
        cs.borderBottomStyle,
        cs.borderBottomColor,
        "|",
        cs.borderLeftWidth,
        cs.borderLeftStyle,
        cs.borderLeftColor
      );
    })();
 
    // DIAG 2: optional loud border, easy to see (comment out after testing)
    (function () {
      if (borderPref === "with") {
        var wrapper =
           doc.querySelector(".entry-wrapper") ||
           doc.querySelector(".print-a4-narrow") ||
          doc.body.firstElementChild;
        if (!wrapper) return;
         // Strong visual to prove it’s applied; remove once confirmed
        wrapper.style.border = "2px dashed red !important";
        console.log("[swprint] TEMP diagnostic border applied (red dashed)");
       }
       }
     })();
     })();
Line 1,526: Line 1,451:
         var txt = (p.textContent || "").replace(/\u00a0/g, " ").trim();
         var txt = (p.textContent || "").replace(/\u00a0/g, " ").trim();
         var onlyBr =
         var onlyBr =
          p.children &&
           p.children.length === 1 &&
           p.children.length === 1 &&
           p.firstElementChild &&
           p.firstElementChild &&
Line 1,538: Line 1,464:
       var root = doc.getElementById("article-content");
       var root = doc.getElementById("article-content");
       if (root) {
       if (root) {
         Array.prototype.slice.call(root.childNodes).forEach(function (n) {
         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, "")) {
           if (n.nodeType === 3 && !n.textContent.replace(/\s+/g, "")) {
             root.removeChild(n);
             root.removeChild(n);
           }
           }
         });
         }
       }
       }
     })();
     })();


     // small inline tweaks
     // inline micro-tweaks for print spacing
     (function () {
     (function () {
       var css =
       var css =
Line 1,553: Line 1,481:
         "  .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-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-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-label-description + .article-description," +
         "  .article-label-description + .article-description," +
         "  .article-label-reflection + .article-reflection," +
         "  .article-label-reflection + .article-reflection," +
Line 1,581: Line 1,498:
     })();
     })();


     // link tweaks
     // link tweaks (wrapping / underline)
     (function () {
     (function () {
       var styleFix = doc.createElement("style");
       var styleFix = doc.createElement("style");
Line 1,587: Line 1,504:
         "@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}}";
         "@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);
       doc.head.appendChild(styleFix);
       var refs = doc.querySelectorAll(".article-external-reference a[href]");
       var refs = doc.querySelectorAll(".article-external-reference a[href]");
       Array.prototype.forEach.call(refs, function (a) {
       Array.prototype.forEach.call(refs, function (a) {
Line 1,708: Line 1,626:
   /* decide source & kick print */
   /* decide source & kick print */
   function swHandlePrintChoice(id, $btn) {
   function swHandlePrintChoice(id, $btn) {
    try {
      console.log("[swprint] swHandlePrintChoice START", {
        id: id,
        btn:
          $btn && $btn[0] && $btn[0].outerHTML
            ? $btn[0].outerHTML.slice(0, 80) + "…"
            : "<none>",
        hasLocalPrintOnly: jQuery(".print-only").length,
      });
    } catch (e) {}
     if ($btn && $btn.data("busy")) return;
     if ($btn && $btn.data("busy")) return;
     if ($btn && $btn.length) $btn.data("busy", true);
     if ($btn && $btn.length) $btn.data("busy", true);
Line 1,728: Line 1,636:
     if (localPrintOnly.length) {
     if (localPrintOnly.length) {
       swHidePrintUI();
       swHidePrintUI();
      console.log("[swprint] using LOCAL .print-only (Entry page)");
       swBuildIframeAndPrint(localPrintOnly.prop("outerHTML"), borderPref, $btn);
       swBuildIframeAndPrint(localPrintOnly.prop("outerHTML"), borderPref, $btn);
       return;
       return;
     }
     }


     // otherwise fetch by title (modal/home list flow)
     // otherwise fetch by title (modal/home)
     var title =
     var title =
       window.currentEntryTitle ||
       window.currentEntryTitle ||
Line 1,747: Line 1,654:
         ? mw.util.getUrl(title)
         ? mw.util.getUrl(title)
         : "/wiki/" + String(title);
         : "/wiki/" + String(title);
     jQuery
     jQuery
       .get(swPrintCacheBust(pageUrl))
       .get(swPrintCacheBust(pageUrl))
Line 1,766: Line 1,674:
   }
   }


  /* bind current choice anchors (defensive, for Entry pages) */
   function swBindChoiceAnchors() {
   function swBindChoiceAnchors() {
     var sel = "#print-with-border, #print-no-border";
     var sel = "#print-with-border, #print-no-border";
Line 1,771: Line 1,680:
     for (var i = 0; i < els.length; i++) {
     for (var i = 0; i < els.length; i++) {
       (function (el) {
       (function (el) {
         if (el.__swChoiceBound) return; // each node once
         if (el.__swChoiceBound) return;
         el.__swChoiceBound = true;
         el.__swChoiceBound = true;


         // make sure node accepts clicks
         // ensure clickable/accessible
         try {
         try {
           el.style.pointerEvents = el.style.pointerEvents || "auto";
           el.style.pointerEvents = el.style.pointerEvents || "auto";
Line 1,781: Line 1,690:
         } catch (e) {}
         } catch (e) {}


         function fire(ev, where) {
         function fire(ev) {
          try {
            console.log("[swprint] CHOICE fire (" + where + "):", el.id);
          } catch (e) {}
           if (ev && ev.preventDefault) ev.preventDefault();
           if (ev && ev.preventDefault) ev.preventDefault();
           if (ev && ev.stopImmediatePropagation) ev.stopImmediatePropagation();
           if (ev && ev.stopImmediatePropagation) ev.stopImmediatePropagation();
Line 1,793: Line 1,699:
         }
         }


         // bind multiple phases/types to dodge libraries that swallow 'click'
         // early + normal phases
        // add these lines among the other addEventListener calls:
         el.addEventListener("pointerdown", fire, true);
         el.addEventListener(
         el.addEventListener("touchstart", fire, true);
          "pointerdown",
         el.addEventListener("mousedown", fire, true);
          function (e) {
         el.addEventListener("click", fire, true);
            fire(e, "pointerdown(capture)");
         el.addEventListener("click", fire, false);
          },
         if (!el.onclick) el.onclick = fire;
          true
        );
         el.addEventListener(
          "touchstart",
          function (e) {
            fire(e, "touchstart(capture)");
          },
          true
        );
         el.addEventListener(
          "mousedown",
          function (e) {
            fire(e, "mousedown(capture)");
          },
          true
        );
        el.addEventListener(
          "pointerup",
          function (e) {
            fire(e, "pointerup");
          },
          true
        );
         el.addEventListener(
          "touchend",
          function (e) {
            fire(e, "touchend");
          },
          true
        );
        el.addEventListener(
          "mouseup",
          function (e) {
            fire(e, "mouseup");
          },
          true
        );
        el.addEventListener(
          "click",
          function (e) {
            fire(e, "click(capture)");
          },
          true
        );
         el.addEventListener(
          "click",
          function (e) {
            fire(e, "click(bubble)");
          },
          false
        );
         if (!el.onclick)
          el.onclick = function (e) {
            return fire(e, "onclick");
          };


         // keyboard
         // keyboard
Line 1,861: Line 1,712:
           function (e) {
           function (e) {
             var k = e.key || e.keyCode;
             var k = e.key || e.keyCode;
             if (k === "Enter" || k === 13 || k === " " || k === 32) {
             if (k === "Enter" || k === 13 || k === " " || k === 32) fire(e);
              fire(e, "keydown");
            }
           },
           },
           true
           true
         );
         );
        try {
          console.log("[swprint] bound element-level handler to", el.id);
        } catch (e) {}
       })(els[i]);
       })(els[i]);
     }
     }
   }
   }


  /* early global catcher (minimal) */
   (function () {
   (function () {
     if (window.__swprintEarlyCatcher) return;
     if (window.__swprintEarlyCatcher) return;
     window.__swprintEarlyCatcher = true;
     window.__swprintEarlyCatcher = true;


     function routeEarly(ev, where) {
     function routeEarly(ev) {
       var t = ev.target;
       var t = ev.target;
       if (!t) return;
       if (!t || !t.closest) return;
       var a = t.closest
       var a = t.closest("a#print-with-border, a#print-no-border");
        ? t.closest("a#print-with-border, a#print-no-border")
        : null;
       if (!a) return;
       if (!a) return;
       try {
       if (ev.preventDefault) ev.preventDefault();
        console.log("[swprint] EARLY-CAPTURE " + where + " ->", a.id);
       if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();
      } catch (e) {}
       if (ev.stopPropagation) ev.stopPropagation();
      ev.preventDefault && ev.preventDefault();
       ev.stopImmediatePropagation && ev.stopImmediatePropagation();
       ev.stopPropagation && ev.stopPropagation();
       swHandlePrintChoice(a.id, (window.jQuery && jQuery(a)) || null);
       swHandlePrintChoice(a.id, (window.jQuery && jQuery(a)) || null);
       return false;
       return false;
     }
     }


    // Catch before anything else can mutate DOM or swallow events
     window.addEventListener("pointerdown", routeEarly, true);
     window.addEventListener(
     window.addEventListener("touchstart", routeEarly, true);
      "pointerdown",
     window.addEventListener("mousedown", routeEarly, true);
      function (e) {
        routeEarly(e, "window:pointerdown");
      },
      true
    );
     window.addEventListener(
      "touchstart",
      function (e) {
        routeEarly(e, "window:touchstart");
      },
      true
    );
     window.addEventListener(
      "mousedown",
      function (e) {
        routeEarly(e, "window:mousedown");
      },
      true
    );
  })();
 
  (function () {
    if (window.__swprintHardCatcherV2) return;
    window.__swprintHardCatcherV2 = true;
 
    function route(ev, where) {
      var t = ev.target;
      var closest =
        t && t.closest
          ? t.closest("a#print-with-border, a#print-no-border")
          : null;
      if (!closest) return;
      try {
        console.log("[swprint] HARD-CAPTURE (" + where + "):", closest.id);
      } catch (e) {}
      ev.preventDefault();
      ev.stopImmediatePropagation && ev.stopImmediatePropagation();
      ev.stopPropagation && ev.stopPropagation();
      var $a = (window.jQuery && jQuery(closest)) || null;
      swHandlePrintChoice(closest.id, $a);
      return false;
    }
 
    // capture high in the tree
    window.addEventListener(
      "click",
      function (e) {
        route(e, "window");
      },
      true
    );
    document.addEventListener(
      "click",
      function (e) {
        route(e, "document");
      },
      true
    );
    document.documentElement.addEventListener(
      "click",
      function (e) {
        route(e, "documentElement");
      },
      true
    );
 
    // if something kills 'click', catch these too
    window.addEventListener(
      "pointerup",
      function (e) {
        route(e, "window:pointerup");
      },
      true
    );
    window.addEventListener(
      "touchend",
      function (e) {
        route(e, "window:touchend");
      },
      true
    );
   })();
   })();


Line 1,988: Line 1,748:
     "#print-button, #print-chooser, #print-options",
     "#print-button, #print-chooser, #print-options",
     function (e) {
     function (e) {
       // click on the main [print]
       // main [print] toggler
      // click on the main [print]
       if (jQuery(e.target).closest("#print-button").length) {
       if (jQuery(e.target).closest("#print-button").length) {
         e.preventDefault();
         e.preventDefault();
         var $chooser = swEnsurePrintChooser();
         var $chooser = swEnsurePrintChooser();
 
         $chooser.css({ position: "absolute", zIndex: 99999 });
        // make sure it sits on top & accepts clicks (diagnostic-safe)
         $chooser.css({
          position: "absolute",
          zIndex: 99999,
        });
 
         $chooser.toggle();
         $chooser.toggle();
         var visible = $chooser.is(":visible");
         var visible = $chooser.is(":visible");
         jQuery("#show-article").toggleClass("print-opts-open", visible);
         jQuery("#show-article").toggleClass("print-opts-open", visible);


         // ensure the currently-rendered anchors are bound (important on Entry pages)
         // ensure anchors are bound (important on Entry pages)
        swBindChoiceAnchors();
 
        // (optional) quick count for sanity
        try {
          console.log("[swprint] chooser toggled; visible=", visible, {
            withCount: document.querySelectorAll('[id="print-with-border"]')
              .length,
            noCount: document.querySelectorAll('[id="print-no-border"]').length,
          });
        } catch (e) {}
 
        // Bind directly on any choice anchors currently in the DOM
         swBindChoiceAnchors();
         swBindChoiceAnchors();
        // run visibility diagnostics on the two buttons
        (function swprintDebugChoices() {
          function dump(id) {
            var list = document.querySelectorAll('[id="' + id + '"]');
            for (var i = 0; i < list.length; i++) {
              var el = list[i];
              var cs = window.getComputedStyle(el);
              var r = el.getBoundingClientRect();
              console.log("[swprint][diag]", id, i, {
                tag: el.tagName,
                display: cs.display,
                visibility: cs.visibility,
                opacity: cs.opacity,
                pointerEvents: cs.pointerEvents,
                rect: {
                  x: Math.round(r.x),
                  y: Math.round(r.y),
                  w: Math.round(r.width),
                  h: Math.round(r.height),
                },
                zIndex: cs.zIndex,
              });
            }
          }
          dump("print-with-border");
          dump("print-no-border");
        })();
         return;
         return;
       }
       }


       // click on a choice link
       // click directly on a choice link (fallback path)
       var $choice = jQuery(e.target).closest(
       var $choice = jQuery(e.target).closest(
         "a#print-with-border, a#print-no-border"
         "a#print-with-border, a#print-no-border"
Line 2,060: Line 1,772:
   );
   );


   // If a widget uses <button> inside the chooser, map it to the nearest id node
   // map any <button> inside chooser to its host anchor
   jQuery(document).on(
   jQuery(document).on(
     "click.swprintChoiceBtn2",
     "click.swprintChoiceBtn2",
Line 2,070: Line 1,782:
       if (!host) return;
       if (!host) return;
       e.preventDefault();
       e.preventDefault();
      console.log("[swprint] BUTTON inside chooser ->", host.id);
       swHandlePrintChoice(host.id, (window.jQuery && jQuery(host)) || null);
       swHandlePrintChoice(host.id, (window.jQuery && jQuery(host)) || null);
     }
     }
   );
   );


   // also hide choices on ESC; your close-button handler already hides them
   // hide choices on ESC
   jQuery(document).on("keydown.swprint", function (e) {
   jQuery(document).on("keydown.swprint", function (e) {
     if (e && e.keyCode === 27) swHidePrintUI();
     if (e && e.keyCode === 27) swHidePrintUI();

Navigation menu