4,554
edits
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
Line 1,669: | Line 1,669: | ||
/* ---------- /Softwear PRINT ---------- */ | /* ---------- /Softwear PRINT ---------- */ | ||
/* === SW PRINT: native fallback for Entry pages === */ | /* === SW PRINT: native fallback for Entry pages (ES5-safe) === */ | ||
(function () { | (function () { | ||
// | // prevent double-binding | ||
if (window.__swPrintNativeBound) return; | if (window.__swPrintNativeBound) { | ||
return; | |||
} | |||
window.__swPrintNativeBound = true; | window.__swPrintNativeBound = true; | ||
// | // ---- tiny helpers ---- | ||
function ensurePrintChooserNative() { | function ensurePrintChooserNative() { | ||
var chooser = document.getElementById("print-chooser"); | var chooser = document.getElementById("print-chooser"); | ||
Line 1,701: | Line 1,703: | ||
var article = document.getElementById("show-article"); | var article = document.getElementById("show-article"); | ||
if (article) { | if (article) { | ||
if (want) article.classList.add("print-opts-open"); | if (want) { | ||
else article.classList.remove("print-opts-open"); | article.classList.add("print-opts-open"); | ||
} else { | |||
article.classList.remove("print-opts-open"); | |||
} | |||
} | |||
if (window.console && console.log) { | |||
console.log("[swprint-native] chooser", want ? "shown" : "hidden"); | |||
} | |||
} | |||
function safeCacheBust(url) { | |||
try { | |||
if (typeof cacheBust === "function") { | |||
return cacheBust(url); | |||
} | |||
} catch (e) { | |||
/* ignore */ | |||
} | } | ||
var sep = url.indexOf("?") > -1 ? "&" : "?"; | |||
return url + sep + "_=" + new Date().getTime(); | |||
} | } | ||
// | // ---- main flow: start printing with preference ---- | ||
function swStartPrint(borderPref) { | function swStartPrint(borderPref) { | ||
console.log("[swprint-native] start with pref:", borderPref); | if (window.console && console.log) { | ||
console.log("[swprint-native] start with pref:", borderPref); | |||
} | |||
try { | try { | ||
preloadFontForPrint | if (typeof preloadFontForPrint === "function") { | ||
preloadFontForPrint(); | |||
} | |||
} catch (e) {} | } catch (e) {} | ||
// 1) Prefer local .print-only (Entry page) | // 1) Prefer local .print-only (Entry page content already on page) | ||
var local = document.querySelector(".print-only"); | var local = document.querySelector(".print-only"); | ||
if (local) { | if (local) { | ||
console.log("[swprint-native] using local .print-only"); | if (window.console && console.log) { | ||
console.log("[swprint-native] using local .print-only"); | |||
} | |||
toggleChooser(false); | toggleChooser(false); | ||
buildIframeAndPrint(local.outerHTML, borderPref); | |||
return; | |||
} | } | ||
// 2) Otherwise fetch by title (modal / | // 2) Otherwise, fetch by title (modal / people page flow) | ||
var title = | var title = null; | ||
window.currentEntryTitle | if ( | ||
(window.mw && | typeof window.currentEntryTitle === "string" && | ||
window.currentEntryTitle | |||
) { | |||
title = window.currentEntryTitle; | |||
} else if ( | |||
window.mw && | |||
mw.config && | |||
typeof mw.config.get === "function" | |||
) { | |||
title = mw.config.get("wgPageName"); | |||
} | |||
if ( | if ( | ||
Line 1,735: | Line 1,768: | ||
!(window.mw && mw.util && typeof mw.util.getUrl === "function") | !(window.mw && mw.util && typeof mw.util.getUrl === "function") | ||
) { | ) { | ||
console.warn( | if (window.console && console.warn) { | ||
console.warn( | |||
"[swprint-native] no title/mw.util; fallback to window.print()" | |||
); | |||
} | |||
window.print(); | |||
return; | |||
} | } | ||
var url = mw.util.getUrl(title); | var url = mw.util.getUrl(title); | ||
url = safeCacheBust(url); | |||
if (window.console && console.log) { | |||
console.log("[swprint-native] fetching:", url); | |||
} | |||
fetch(url, { credentials: "same-origin" }) | // Use fetch if present; fall back to XHR | ||
if (window.fetch) { | |||
fetch(url, { credentials: "same-origin" }) | |||
.then(function (r) { | |||
return r.text(); | |||
}) | |||
.then(function (html) { | |||
var | handleFetchedHtml(html, borderPref); | ||
if ( | }) | ||
console.warn( | .catch(function (err) { | ||
if (window.console && console.warn) { | |||
console.warn( | |||
"[swprint-native] fetch failed; window.print()", | |||
err | |||
); | |||
} | |||
window.print(); | |||
}); | |||
} else { | |||
var xhr = new XMLHttpRequest(); | |||
xhr.open("GET", url, true); | |||
xhr.withCredentials = true; | |||
xhr.onreadystatechange = function () { | |||
if (xhr.readyState === 4) { | |||
if (xhr.status >= 200 && xhr.status < 300) { | |||
handleFetchedHtml(xhr.responseText, borderPref); | |||
} else { | |||
if (window.console && console.warn) { | |||
console.warn( | |||
"[swprint-native] XHR failed; window.print()", | |||
xhr.status | |||
); | |||
} | |||
window.print(); | |||
} | |||
} | } | ||
}; | |||
xhr.send(null); | |||
} | } | ||
. | |||
} | } | ||
// | function handleFetchedHtml(html, borderPref) { | ||
var tmp = document.createElement("div"); | |||
tmp.innerHTML = html; | |||
var printOnly = tmp.querySelector(".print-only"); | |||
if (!printOnly) { | |||
if (window.console && console.warn) { | |||
console.warn( | |||
"[swprint-native] no .print-only in fetched page; window.print()" | |||
); | |||
} | |||
window.print(); | |||
return; | |||
} | |||
toggleChooser(false); | |||
buildIframeAndPrint(printOnly.outerHTML, borderPref); | |||
} | |||
// ---- iframe build + print (ES5) ---- | |||
function buildIframeAndPrint(printHtml, borderPref) { | function buildIframeAndPrint(printHtml, borderPref) { | ||
console.log("[swprint-native] buildIframeAndPrint()"); | if (window.console && console.log) { | ||
console.log("[swprint-native] buildIframeAndPrint()"); | |||
} | |||
var iframe = document.createElement("iframe"); | var iframe = document.createElement("iframe"); | ||
Line 1,796: | Line 1,869: | ||
var cssUrl = | var cssUrl = | ||
"/index.php?title=MediaWiki:Print.css&action=raw&ctype=text/css"; | "/index.php?title=MediaWiki:Print.css&action=raw&ctype=text/css"; | ||
cssUrl = safeCacheBust(cssUrl); | |||
var linkCss = doc.createElement("link"); | var linkCss = doc.createElement("link"); | ||
linkCss.rel = "stylesheet"; | linkCss.rel = "stylesheet"; | ||
linkCss.href = cssUrl; | linkCss.href = cssUrl; | ||
var cssLoaded = new Promise(function ( | |||
var cssLoaded = new Promise(function (resolve) { | |||
linkCss.onload = function () { | linkCss.onload = function () { | ||
console.log("[swprint-native] print CSS loaded"); | if (window.console && console.log) { | ||
console.log("[swprint-native] print CSS loaded"); | |||
} | |||
resolve(); | |||
}; | }; | ||
linkCss.onerror = function () { | linkCss.onerror = function () { | ||
console.warn("[swprint-native] print CSS failed"); | if (window.console && console.warn) { | ||
console.warn("[swprint-native] print CSS failed"); | |||
} | |||
resolve(); | |||
}; | }; | ||
}); | }); | ||
Line 1,824: | Line 1,900: | ||
doc.head.appendChild(linkCss); | doc.head.appendChild(linkCss); | ||
// content | |||
doc.body.innerHTML = printHtml; | doc.body.innerHTML = printHtml; | ||
// border pref | // border pref | ||
var root = doc.documentElement; | var root = doc.documentElement; | ||
if (borderPref === "without") root.classList.add("print-no-border"); | if (borderPref === "without") { | ||
else root.classList.remove("print-no-border"); | root.classList.add("print-no-border"); | ||
console.log("[swprint-native] borderPref applied:", borderPref); | } else { | ||
root.classList.remove("print-no-border"); | |||
} | |||
if (window.console && console.log) { | |||
console.log("[swprint-native] borderPref applied:", borderPref); | |||
} | |||
// | // minimal inline tweaks | ||
var style = doc.createElement("style"); | var style = doc.createElement("style"); | ||
style. | style.type = "text/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}[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}}"; | style.appendChild( | ||
doc.createTextNode( | |||
"@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); | doc.head.appendChild(style); | ||
var styleFix = doc.createElement("style"); | var styleFix = doc.createElement("style"); | ||
styleFix. | styleFix.type = "text/css"; | ||
"@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}}"; | styleFix.appendChild( | ||
doc.createTextNode( | |||
"@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); | ||
// wait helpers | // wait helpers | ||
function nextFrame() { | function nextFrame(resolve) { | ||
(iframe.contentWindow.requestAnimationFrame || setTimeout)(resolve, 0); | |||
} | } | ||
var waitNextFrame = new Promise(function (resolve) { | |||
nextFrame(resolve); | |||
}); | |||
var waitFonts = | var waitFonts = | ||
doc.fonts && doc.fonts.ready | doc.fonts && doc.fonts.ready | ||
? Promise.race([ | ? Promise.race([ | ||
doc.fonts.ready, | doc.fonts.ready, | ||
new Promise((r) | new Promise(function (r) { | ||
setTimeout(r, 1200); | |||
}), | |||
]) | ]) | ||
: Promise.resolve(); | : Promise.resolve(); | ||
Promise.all([cssLoaded, waitFonts, | Promise.all([cssLoaded, waitFonts, waitNextFrame]).then(function () { | ||
console.log("[swprint-native] resources ready; print()"); | if (window.console && console.log) { | ||
console.log("[swprint-native] resources ready; print()"); | |||
} | |||
var numEl = doc.querySelector(".article-entry-number"); | var numEl = doc.querySelector(".article-entry-number"); | ||
var entryNum = ""; | var entryNum = ""; | ||
Line 1,868: | Line 1,963: | ||
var desiredTitle = | var desiredTitle = | ||
(entryNum ? entryNum + "." : "") + "softwear.directory"; | (entryNum ? entryNum + "." : "") + "softwear.directory"; | ||
var oldIframeTitle = doc.title; | var oldIframeTitle = doc.title; | ||
var oldParentTitle = document.title; | var oldParentTitle = document.title; | ||
Line 1,877: | Line 1,973: | ||
} catch (e) {} | } catch (e) {} | ||
setTimeout(function () { | setTimeout(function () { | ||
if (iframe.parentNode) iframe.parentNode.removeChild(iframe); | if (iframe.parentNode) { | ||
iframe.parentNode.removeChild(iframe); | |||
} | |||
}, 100); | }, 100); | ||
console.log("[swprint-native] afterprint cleanup"); | if (window.console && console.log) { | ||
console.log("[swprint-native] afterprint cleanup"); | |||
} | |||
}; | }; | ||
Line 1,888: | Line 1,988: | ||
iframe.contentWindow.print(); | iframe.contentWindow.print(); | ||
// safety cleanup if onafterprint never fires | |||
setTimeout(function () { | setTimeout(function () { | ||
try { | try { | ||
Line 1,893: | Line 1,994: | ||
document.title = oldParentTitle; | document.title = oldParentTitle; | ||
} catch (e) {} | } catch (e) {} | ||
if (iframe.parentNode) iframe.parentNode.removeChild(iframe); | if (iframe.parentNode) { | ||
console.log("[swprint-native] timeout cleanup"); | iframe.parentNode.removeChild(iframe); | ||
}, | } | ||
if (window.console && console.log) { | |||
console.log("[swprint-native] timeout cleanup"); | |||
} | |||
}, 1500); | |||
}); | }); | ||
} | } | ||
// | // ---- bind native clicks ---- | ||
var printBtn = document.getElementById("print-button"); | var printBtn = document.getElementById("print-button"); | ||
if (printBtn) { | if (printBtn) { | ||
Line 1,905: | Line 2,010: | ||
"click", | "click", | ||
function (e) { | function (e) { | ||
e.preventDefault(); | if (e && e.preventDefault) { | ||
console.log("[swprint-native] print-button clicked"); | e.preventDefault(); | ||
} | |||
if (window.console && console.log) { | |||
console.log("[swprint-native] print-button clicked"); | |||
} | |||
toggleChooser(); | toggleChooser(); | ||
}, | }, | ||
Line 1,913: | Line 2,022: | ||
} | } | ||
function onChoice(e) { | function onChoice(e) { | ||
var | var t = e.target || e.srcElement; | ||
if (!a) return; | var a = null; | ||
if ( | // emulate closest("a") in ES5 | ||
e.preventDefault(); | while (t && t !== document) { | ||
var pref = | if (t.tagName && t.tagName.toLowerCase() === "a") { | ||
console.log("[swprint-native] choice clicked:", pref); | a = t; | ||
break; | |||
} | |||
t = t.parentNode; | |||
} | |||
if (!a) { | |||
return; | |||
} | |||
var id = a.id || ""; | |||
if (id !== "print-with-border" && id !== "print-no-border") { | |||
return; | |||
} | |||
if (e && e.preventDefault) { | |||
e.preventDefault(); | |||
} | |||
var pref = id === "print-no-border" ? "without" : "with"; | |||
if (window.console && console.log) { | |||
console.log("[swprint-native] choice clicked:", pref); | |||
} | |||
swStartPrint(pref); | swStartPrint(pref); | ||
} | } | ||
// if already | // bind existing anchors (if already in DOM) | ||
var aWith = document.getElementById("print-with-border"); | |||
var | if (aWith) { | ||
aWith.addEventListener("click", onChoice, false); | |||
} | } | ||
var aNo = document.getElementById("print-no-border"); | |||
if (aNo) { | |||
aNo.addEventListener("click", onChoice, false); | |||
} | |||
// and delegate for dynamically created chooser | // and delegate for dynamically created chooser | ||
document.addEventListener("click", onChoice, false); | document.addEventListener("click", onChoice, false); | ||
console.log("[swprint-native] fallback bound"); | if (window.console && console.log) { | ||
console.log("[swprint-native] fallback bound"); | |||
} | |||
})(); | })(); | ||