4,554
edits
No edit summary |
No edit summary |
||
Line 1,282: | Line 1,282: | ||
if ($chooser.length) return $chooser; | if ($chooser.length) return $chooser; | ||
$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 | // 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 | ev = ev || window.event; | ||
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; | ||
if (ev.preventDefault) ev.preventDefault(); | |||
if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); | |||
if (ev.stopPropagation) ev.stopPropagation(); | |||
swHandlePrintChoice(id, (window.jQuery && jQuery(a)) || null); | |||
ev.stopImmediatePropagation | |||
ev.stopPropagation | |||
swHandlePrintChoice(id, jQuery(a)); | |||
return false; | return false; | ||
} | } | ||
$chooser.on( | $chooser.on("pointerdown", chooserFire); | ||
$chooser.on("touchstart", chooserFire); | |||
$chooser.on("mousedown", chooserFire); | |||
$chooser.on("click", chooserFire); | |||
$chooser.on("touchstart", chooserFire | |||
$chooser.on("mousedown", chooserFire | |||
$chooser.on("click", chooserFire | |||
$chooser.data("swBound", true); | $chooser.data("swBound", true); | ||
} | } | ||
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) {} | ||
})(); | })(); | ||
/* core: build iframe and print */ | /* core: build iframe and print */ | ||
function swBuildIframeAndPrint(printHtml, borderPref, $btn) { | function swBuildIframeAndPrint(printHtml, borderPref, $btn) { | ||
// 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 = | linkCss.onload = resolve; | ||
linkCss.onerror = resolve; | |||
linkCss.onerror = | |||
}); | }); | ||
Line 1,403: | Line 1,381: | ||
doc.body.innerHTML = printHtml; | doc.body.innerHTML = printHtml; | ||
// | // 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, | ||
"" | "" | ||
); | ); | ||
} | } | ||
})(); | })(); | ||
// | // OPTIONAL: glue label + body together (extra safety vs. page breaks) | ||
(function () { | (function () { | ||
var style = doc.createElement("style"); | var style = doc.createElement("style"); | ||
style. | style.textContent = | ||
"@media print{.sw-keep{break-inside:avoid;page-break-inside:avoid;}}"; | |||
doc.head.appendChild(style); | doc.head.appendChild(style); | ||
var pairs = [ | |||
[".article-label-description", ".article-description"], | |||
[".article-label-reflection", ".article-reflection"], | |||
var | [".article-label-external-reference", ".article-external-reference"], | ||
[".article-label-quote", ".article-quote"], | |||
[".article-label-modification-date", ".article-modification-date"], | |||
]; | |||
for (var i = 0; i < pairs.length; i++) { | |||
var labelSel = pairs[i][0]; | |||
var bodySel = pairs[i][1]; | |||
var labels = doc.querySelectorAll(labelSel); | |||
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); | |||
} | |||
} | } | ||
})(); | })(); | ||
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). | 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); | ||
} | } | ||
} | } | ||
} | } | ||
})(); | })(); | ||
// | // 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;}" + | ||
" .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) { | ||
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(); | ||
swBuildIframeAndPrint(localPrintOnly.prop("outerHTML"), borderPref, $btn); | swBuildIframeAndPrint(localPrintOnly.prop("outerHTML"), borderPref, $btn); | ||
return; | return; | ||
} | } | ||
// otherwise fetch by title (modal/home | // 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; | if (el.__swChoiceBound) return; | ||
el.__swChoiceBound = true; | el.__swChoiceBound = true; | ||
// | // 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 | function fire(ev) { | ||
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: | ||
} | } | ||
// | // early + normal phases | ||
el.addEventListener("pointerdown", fire, true); | |||
el.addEventListener( | 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; | |||
el.addEventListener( | |||
el.addEventListener( | |||
el.addEventListener( | |||
el.addEventListener( | |||
if (!el.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); | ||
}, | }, | ||
true | true | ||
); | ); | ||
})(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 | function routeEarly(ev) { | ||
var t = ev.target; | var t = ev.target; | ||
if (!t) return; | if (!t || !t.closest) return; | ||
var a = | var a = t.closest("a#print-with-border, a#print-no-border"); | ||
if (!a) return; | if (!a) return; | ||
if (ev.preventDefault) ev.preventDefault(); | |||
if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); | |||
if (ev.stopPropagation) ev.stopPropagation(); | |||
ev.stopImmediatePropagation | |||
ev.stopPropagation | |||
swHandlePrintChoice(a.id, (window.jQuery && jQuery(a)) || null); | swHandlePrintChoice(a.id, (window.jQuery && jQuery(a)) || null); | ||
return false; | return false; | ||
} | } | ||
window.addEventListener("pointerdown", routeEarly, true); | |||
window.addEventListener( | window.addEventListener("touchstart", routeEarly, true); | ||
window.addEventListener("mousedown", routeEarly, true); | |||
window.addEventListener( | |||
window.addEventListener( | |||
})(); | })(); | ||
Line 1,988: | Line 1,748: | ||
"#print-button, #print-chooser, #print-options", | "#print-button, #print-chooser, #print-options", | ||
function (e) { | function (e) { | ||
// | // main [print] toggler | ||
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 }); | |||
$chooser.css({ | |||
$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 | // ensure anchors are bound (important on Entry pages) | ||
swBindChoiceAnchors(); | swBindChoiceAnchors(); | ||
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: | ||
); | ); | ||
// | // 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(); | ||
swHandlePrintChoice(host.id, (window.jQuery && jQuery(host)) || null); | swHandlePrintChoice(host.id, (window.jQuery && jQuery(host)) || null); | ||
} | } | ||
); | ); | ||
// | // 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(); |