4,554
edits
| No edit summary | No edit summary | ||
| Line 1,370: | Line 1,370: | ||
|          // Remove “empty” optional sections so they don’t leave gaps in print. |          // Remove “empty” optional sections so they don’t leave gaps in print. | ||
|          //  |          // --- PRUNE EMPTY PRINT SECTIONS (ES5-safe) --- | ||
|          var  |          (function () { | ||
|           var content = doc.getElementById("article-content"); | |||
|           if (!content) return; | |||
|           // Remove pure-whitespace text nodes so :empty checks can work | |||
|           function stripWhitespaceTextNodes(node) { | |||
|             var i, child; | |||
|             for (i = node.childNodes.length - 1; i >= 0; i--) { | |||
|               child = node.childNodes[i]; | |||
|               if ( | |||
|                 child.nodeType === 3 && | |||
|                 (!child.nodeValue || | |||
|                   child.nodeValue.replace(/\u00a0/g, " ").trim() === "") | |||
|               ) { | |||
|                "  |                 node.removeChild(child); | ||
|                } else if (child.nodeType === 1) { | |||
|                "  |                 stripWhitespaceTextNodes(child); | ||
|               } | |||
|             } | |||
|                "   |           } | ||
|           stripWhitespaceTextNodes(content); | |||
|           function isEffectivelyEmpty(el) { | |||
|             if (!el) return true; | |||
|             // images make it non-empty | |||
|             if (el.getElementsByTagName("img").length) return false; | |||
|             // ignore <br> | |||
|             var brs = el.getElementsByTagName("br"); | |||
|             while (brs.length) brs[0].parentNode.removeChild(brs[0]); | |||
|             var txt = (el.textContent || "").replace(/\u00a0/g, " ").trim(); | |||
|             return txt.length === 0; | |||
|           } | |||
|           function rm(el) { | |||
|             if (el && el.parentNode) el.parentNode.removeChild(el); | |||
|           } | |||
|           // Label/content pairs to prune together | |||
|           var PAIRS = [ | |||
|             ["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"], | |||
|           ]; | |||
|           // Remove empty metadata columns, then whole metadata if all empty | |||
|           (function pruneMetadata() { | |||
|             var meta = content.querySelector(".article-metadata"); | |||
|             if (!meta) return; | |||
|             var cols = meta.querySelectorAll(".article-metadata-column"); | |||
|             var nonEmptyCols = 0; | |||
|             for (var i = 0; i < cols.length; i++) { | |||
|                var val = cols[i].querySelector(".article-metadata-value"); | |||
|               if (isEffectivelyEmpty(val)) { | |||
|                 rm(cols[i]); | |||
|               } else { | |||
|                 nonEmptyCols++; | |||
|               } | |||
|             } | |||
|             if (!nonEmptyCols) rm(meta); | |||
|           })(); | |||
|           // Prune each label/content pair if content is empty (or missing) | |||
|           for (var i = 0; i < PAIRS.length; i++) { | |||
|             var label = content.querySelector("." + PAIRS[i][0]); | |||
|             var body = content.querySelector("." + PAIRS[i][1]); | |||
|             if (!body || isEffectivelyEmpty(body)) { | |||
|               rm(label); | |||
|                rm(body); | |||
|             } | |||
|           } | |||
|           // If images wrapper has no <img>, remove it | |||
|           var imagesWrap = content.querySelector(".article-images"); | |||
|           if (imagesWrap && !imagesWrap.getElementsByTagName("img").length) { | |||
|             rm(imagesWrap); | |||
|           } | |||
|           // After pruning, strip whitespace again so first/last-child calcs are clean | |||
|           stripWhitespaceTextNodes(content); | |||
|           // Mark the LAST visible block so we can remove its hairline/padding | |||
|           var kids = content.children; | |||
|           if (kids && kids.length) { | |||
|             // Remove any previous marker | |||
|             var old = content.querySelector(".no-rule-last"); | |||
|             if (old) | |||
|                old.className = old.className | |||
|                 .replace(/\bno-rule-last\b/g, "") | |||
|                 .trim(); | |||
|             kids[kids.length - 1].className += " no-rule-last"; | |||
|           } | |||
|           // Tiny CSS to kill rule & padding on the last element and tighten rhythm | |||
|           var tidy = doc.createElement("style"); | |||
|           tidy.type = "text/css"; | |||
|           tidy.appendChild( | |||
|             doc.createTextNode( | |||
|                "@media print {" + | |||
|                 "  #article-content > * { margin-top:0 !important; margin-bottom:0 !important; }" + | |||
|                 "  #article-content > * + * { margin-top:2mm !important; }" + | |||
|                 "  /* kill hairline/padding on last visible block */" + | |||
|                 "  #article-content > .no-rule-last { padding-bottom:0 !important; }" + | |||
|                 "  #article-content > .no-rule-last::after { content:none !important; display:none !important; }" + | |||
|                 "  /* paragraphs inside rich text */" + | |||
|                 "  .article-description p, .article-reflection p { margin:0 0 1.2mm 0 !important; }" + | |||
|                 "  .article-description p:last-child, .article-reflection p:last-child { margin-bottom:0 !important; }" + | |||
|                 "}" | |||
|             ) | |||
|           ); | |||
|           doc.head.appendChild(tidy); | |||
|         })(); | |||
|          // --- PDF-friendly links for Chrome on macOS --- |          // --- PDF-friendly links for Chrome on macOS --- | ||