MediaWiki:Common.js: Difference between revisions

Jump to navigation Jump to search
no edit summary
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.
         // --- Collapse empty sections & their labels, and tidy any leftover spacing ---
         // --- DEBUG + robust removal of empty sections in the print iframe ---
         (function tidyPrint(doc) {
         (function debugAndTidyPrint(doc) {
           // 1) Utility: detect “visually empty” blocks
           // Toggle verbose output / colored outlines
           function isVisuallyEmpty(el) {
          var DEBUG_PRINT = true;
 
          // 0) Add a tag so we can scope debug styles safely
          doc.documentElement.setAttribute("data-print-ifr", "1");
 
          // 1) Debug CSS (visualize what the iframe thinks exists)
          if (DEBUG_PRINT) {
            var dbg = doc.createElement("style");
            dbg.textContent =
              "[data-print-ifr] .article-label-description{outline:1px solid #1e90ff!important}" +
              "[data-print-ifr] .article-description{outline:1px dashed #1e90ff!important}" +
              "[data-print-ifr] .article-label-reflection{outline:1px solid #aa00ff!important}" +
              "[data-print-ifr] .article-reflection{outline:1px dashed #aa00ff!important}" +
              "[data-print-ifr] .article-label-external-reference{outline:1px solid #00aa88!important}" +
              "[data-print-ifr] .article-external-reference{outline:1px dashed #00aa88!important}" +
              "[data-print-ifr] .article-label-quote{outline:1px solid #ff8800!important}" +
              "[data-print-ifr] .article-quote{outline:1px dashed #ff8800!important}" +
              "[data-print-ifr] .article-images{outline:1px dashed #e91e63!important}" +
              // show the last-child hairline situation
              "@media print{" +
              "[data-print-ifr] #article-content>:last-child{outline:2px solid red!important}" +
              "}";
            doc.head.appendChild(dbg);
          }
 
          // 2) Helpers
          function cleanText(node) {
            var txt = (node.textContent || "")
              .replace(/\u00A0/g, " ") // nbsp
              .replace(/\u200B/g, "") // zero-width
              .replace(/\s+/g, " ") // collapse
              .trim();
            return txt;
          }
 
           function looksEmptyBlock(el) {
             if (!el) return true;
             if (!el) return true;


             // If it contains any real content, bail
             // If it has meaningful children, it's not empty
             if (
             if (
               el.querySelector("img, video, audio, iframe, svg, object, embed")
               el.querySelector("img,video,audio,iframe,svg,object,embed,canvas")
             )
             )
               return false;
               return false;
             if (el.querySelector("a[href]")) return false;
             if (el.querySelector("a[href]")) return false;


             // Remove <br> & empty <p> shells before checking text
             // Clone to strip <br> and empty <p> safely
            // (work on a shallow clone so we don't touch the live node yet)
             var c = el.cloneNode(true),
             var clone = el.cloneNode(true);
              i;
             var i,
 
              brs = clone.getElementsByTagName("br");
            // remove <br>
             var brs = c.getElementsByTagName("br");
             for (i = brs.length - 1; i >= 0; i--)
             for (i = brs.length - 1; i >= 0; i--)
               brs[i].parentNode.removeChild(brs[i]);
               brs[i].parentNode.removeChild(brs[i]);


             // Remove <p> that are empty/whitespace only
             // remove empty/whitespace-only <p>
             var ps = clone.getElementsByTagName("p");
             var ps = c.getElementsByTagName("p");
             for (i = ps.length - 1; i >= 0; i--) {
             for (i = ps.length - 1; i >= 0; i--) {
               var t = (ps[i].textContent || "")
               var t = cleanText(ps[i]);
                .replace(/\u00A0/g, " ")
                .replace(/\u200B/g, "")
                .replace(/\s+/g, " ")
                .trim();
               if (!t) ps[i].parentNode.removeChild(ps[i]);
               if (!t) ps[i].parentNode.removeChild(ps[i]);
             }
             }


             // Now inspect text
             return cleanText(c) === "";
            var txt = (clone.textContent || "")
              .replace(/\u00A0/g, " ") // NBSP
              .replace(/\u200B/g, "") // zero-width space
              .replace(/\s+/g, " ") // collapse spaces
              .trim();
 
            return !txt;
           }
           }


          // 2) Remove block + its label if empty
           function collapsePair(labelSel, blockSel) {
           function removePair(blockSel, labelSel) {
             var block = doc.querySelector(blockSel);
             var block = doc.querySelector(blockSel);
             if (block && isVisuallyEmpty(block)) {
            var label = doc.querySelector(labelSel);
               // Remove preceding label if it matches
             if (!block && !label) {
              if (labelSel) {
               if (DEBUG_PRINT)
                var prev = block.previousElementSibling;
                console.log("[print] pair missing:", labelSel, blockSel);
                if (
              return;
                  prev &&
            }
                  prev.matches &&
 
                  prev.matches(labelSel) &&
            var empty = block ? looksEmptyBlock(block) : true;
                  prev.parentNode
 
                 ) {
            if (DEBUG_PRINT) {
                  prev.parentNode.removeChild(prev);
              console.log("[print] check", blockSel, {
                }
                exists: !!block,
              }
                empty: empty,
               if (block.parentNode) block.parentNode.removeChild(block);
                textLen: block ? cleanText(block).length : 0,
              });
            }
 
            if (empty) {
              if (label && label.parentNode)
                 label.parentNode.removeChild(label);
               if (block && block.parentNode)
                block.parentNode.removeChild(block);
             }
             }
           }
           }


           // 3) Images wrapper: only keep if it actually has a usable <img src>
           // 3) Images: drop wrapper if no usable <img src>
           (function () {
           (function () {
             var wrap = doc.querySelector(".article-images");
             var wrap = doc.querySelector(".article-images");
Line 1,446: Line 1,478:
               }
               }
             }
             }
            if (DEBUG_PRINT)
              console.log(
                "[print] images wrapper, hasImg:",
                hasSrc,
                "count:",
                imgs.length
              );
             if (!hasSrc && wrap.parentNode) wrap.parentNode.removeChild(wrap);
             if (!hasSrc && wrap.parentNode) wrap.parentNode.removeChild(wrap);
           })();
           })();


           // 4) Optional sections
           // 4) Collapse optional sections
           removePair(".article-description", ".article-label-description");
           collapsePair(".article-label-description", ".article-description");
           removePair(".article-reflection", ".article-label-reflection");
           collapsePair(".article-label-reflection", ".article-reflection");
           removePair(
           collapsePair(
             ".article-external-reference",
             ".article-label-external-reference",
             ".article-label-external-reference"
             ".article-external-reference"
           );
           );
           removePair(".article-quote", ".article-label-quote");
           collapsePair(".article-label-quote", ".article-quote");


           // 5) Metadata grid: drop if all values are empty
           // 5) Metadata grid: remove if all values empty
           (function () {
           (function () {
             var meta = doc.querySelector(".article-metadata");
             var meta = doc.querySelector(".article-metadata");
Line 1,466: Line 1,505:
               i;
               i;
             for (i = 0; i < vals.length; i++) {
             for (i = 0; i < vals.length; i++) {
               if (!isVisuallyEmpty(vals[i])) {
               if (!looksEmptyBlock(vals[i])) {
                 allEmpty = false;
                 allEmpty = false;
                 break;
                 break;
               }
               }
             }
             }
            if (DEBUG_PRINT)
              console.log("[print] metadata allEmpty:", allEmpty);
             if (allEmpty && meta.parentNode) meta.parentNode.removeChild(meta);
             if (allEmpty && meta.parentNode) meta.parentNode.removeChild(meta);
           })();
           })();


           // 6) Title link row: remove the link bar if it ended up empty (no anchors)
           // 6) Link bar: remove if it has no anchors
           (function () {
           (function () {
             var bar = doc.querySelector(".link-pdf");
             var bar = doc.querySelector(".link-pdf");
             if (!bar) return;
             var hasLink =
             if (!bar.querySelector("a[href]") && bar.parentNode)
              bar && bar.querySelector && bar.querySelector("a[href]");
             if (DEBUG_PRINT)
              console.log("[print] link-pdf hasLink:", !!hasLink);
            if (bar && !hasLink && bar.parentNode)
               bar.parentNode.removeChild(bar);
               bar.parentNode.removeChild(bar);
           })();
           })();


           // 7) Remove any now-empty label that wasn’t paired (defensive)
           // 7) Kill truly empty <p> shells that still occupy height
          var strayLabels = doc.querySelectorAll(
          (function () {
            ".article-label-description, .article-label-reflection, " +
            var ps = doc.querySelectorAll("#article-content p");
              ".article-label-external-reference, .article-label-quote"
            for (var i = 0; i < ps.length; i++) {
          );
              var p = ps[i];
          for (var i = 0; i < strayLabels.length; i++) {
               if (!p.children.length && cleanText(p) === "" && p.parentNode) {
            if (strayLabels[i].parentNode)
                if (DEBUG_PRINT)
               strayLabels[i].parentNode.removeChild(strayLabels[i]);
                  console.log(
          }
                    "[print] remove empty <p>",
 
                    p.className || "(no class)"
          // 8) Kill truly empty paragraphs that may still add height
                  );
          var empties = doc.querySelectorAll("#article-content p");
                p.parentNode.removeChild(p);
          for (var j = 0; j < empties.length; j++) {
              }
            var text = (empties[j].textContent || "")
              .replace(/\u00A0/g, " ")
              .replace(/\u200B/g, "")
              .trim();
            if (
              !text &&
              empties[j].children.length === 0 &&
              empties[j].parentNode
            ) {
              empties[j].parentNode.removeChild(empties[j]);
             }
             }
           }
           })();


           // 9) Hide the hairline on the very last block to avoid a “phantom gap”
           // 8) Remove trailing hairline padding on last visible block
           var css = doc.createElement("style");
           (function () {
          css.textContent =
            var fix = doc.createElement("style");
            "@media print{#article-content>:last-child{padding-bottom:0!important;}" +
            fix.textContent =
            "#article-content>:last-child::after{content:none!important;}}";
              "@media print{" +
          doc.head.appendChild(css);
              "#article-content>:last-child{padding-bottom:0!important}" +
              "#article-content>:last-child::after{content:none!important}" +
              "}";
            doc.head.appendChild(fix);
          })();
         })(doc);
         })(doc);


Navigation menu