1/* B9 â "Leia também" e "Relacionados" AUTOMÃTICOS no meio do artigo. 2 O editor cola só um slot vazio: 3 <div data-readnext></div> â 1 matéria, com miniatura 4 <div data-readnext="texto"></div> â 1 matéria, só texto 5 <div data-readnext-2></div> â DUAS lado a lado (bloco "Relacionados") 6 7 Todos são preenchidos com matérias do POOL renderizado no servidor 8 (<template id="b9-readnext-pool"> no post.hbs â mesma editoria, mais 9 recentes, sem episódios/podcasts). 10 11 NÃO REPETE o que já está na página: antes de preencher, coleta os links já 12 exibidos na barra lateral ("Leia também" / "Mais lidas") e no "Fique por 13 dentro", e pula do pool qualquer relacionada que já apareça ali (compara por 14 pathname). Também não repete entre slots do mesmo post. Adapta sozinho ao que 15 a lateral mostra (membro vê 4, anônimo vê 2). 16 17 Zero preenchimento manual, zero chamada de API (o pool já vem no HTML). Sem 18 relacionada NOVA disponÃvel â o slot é REMOVIDO (nunca aparece vazio); no 19 2-up, sem DUAS novas o bloco inteiro some (não vira uma só). 20 TÃtulos entre aspas viram itálico via window.b9ApplyQuoteItalics (b9-titles.js, 21 carregado ANTES deste). */ 22(function () { 23 "use strict"; 24 25 var slots = document.querySelectorAll(".prose [data-readnext], .prose [data-readnext-2]"); 26 if (!slots.length) return; 27 28 var pool = document.getElementById("b9-readnext-pool"); 29 var items = pool && pool.content 30 ? Array.prototype.slice.call(pool.content.querySelectorAll("a.b9-readnext")) 31 : []; 32 33 function key(href) { 34 try { return new URL(href, location.href).pathname.replace(/\/+$/, ""); } 35 catch (e) { return href || ""; } 36 } 37 function isFlat(v) { 38 v = (v || "").toLowerCase(); 39 return v === "texto" || v === "flat" || v === "text"; 40 } 41 42 // Links já visÃveis fora do corpo â não repetir. Cobre a sidebar 43 // (.art-aside: "Leia também" server-rendered + "Mais lidas") e o 44 // "Fique por dentro" (.art-related), ambos no DOM quando este script roda. 45 var used = {}; 46 document.querySelectorAll(".art-aside a[href], .art-related a[href]").forEach(function (a) { 47 used[key(a.getAttribute("href") || a.href)] = 1; 48 }); 49 50 var i = 0; 51 function nextItem() { 52 while (i < items.length) { 53 var it = items[i++]; 54 var k = key(it.getAttribute("href")); 55 if (used[k]) continue; // já aparece na lateral / já usado num slot 56 used[k] = 1; 57 return it; 58 } 59 return null; 60 } 61 // Duas de uma vez, tudo ou nada: sem DUAS novas, devolve o que pegou pro 62 // pool (não gasta relacionada num bloco que não vai renderizar). 63 function takePair() { 64 var mark = i, got = [], it; 65 while (got.length < 2 && (it = nextItem())) got.push(it); 66 if (got.length === 2) return got; 67 got.forEach(function (x) { delete used[key(x.getAttribute("href"))]; }); 68 i = mark; 69 return null; 70 } 71 function titleOf(src) { 72 var t = src.querySelector(".b9-readnext__title"); 73 return t ? t.textContent : ""; 74 } 75 76 // ââ 1 matéria (Leia também) âââââââââââââââââââââââââââââââââââââââââââ 77 function fillOne(slot) { 78 var src = nextItem(); 79 if (!src) { slot.remove(); return; } // sem relacionada nova â some 80 81 var flat = isFlat(slot.getAttribute("data-readnext")); 82 var a = src.cloneNode(true); 83 var thumb = a.getAttribute("data-thumb"); 84 a.removeAttribute("data-thumb"); 85 a.removeAttribute("data-cat"); 86 87 if (!flat && thumb) { 88 var img = document.createElement("img"); 89 img.className = "b9-readnext__thumb"; 90 img.src = thumb; 91 img.alt = ""; 92 img.loading = "lazy"; 93 a.appendChild(img); 94 } else { 95 // sem imagem (pedido "texto" OU relacionada sem feature_image) â versão flat 96 a.classList.add("b9-readnext--flat"); 97 } 98 99 slot.replaceWith(a); 100 if (window.b9ApplyQuoteItalics) window.b9ApplyQuoteItalics(a); 101 } 102 103 // ââ 2 matérias lado a lado (Relacionados) âââââââââââââââââââââââââââââ 104 function fillPair(slot) { 105 var pair = takePair(); 106 if (!pair) { slot.remove(); return; } 107 108 var wrap = document.createElement("div"); 109 wrap.className = "b9-related"; 110 var eyebrow = document.createElement("span"); 111 eyebrow.className = "b9-rn-eyebrow"; 112 eyebrow.textContent = "Relacionados"; 113 var grid = document.createElement("div"); 114 grid.className = "b9-related__grid"; 115 var missing = false;
116 117 pair.forEach(function (src) { 118 var a = document.createElement("a"); 119 a.className = "b9-related__item"; 120 a.href = src.getAttribute("href"); 121 122 var thumb = src.getAttribute("data-thumb"); 123 if (!thumb) missing = true; 124 else { 125 var img = document.createElement("img"); 126 img.className = "b9-related__thumb"; 127 img.src = thumb; 128 img.alt = ""; 129 img.loading = "lazy"; 130 a.appendChild(img); 131 } 132 133 var cat = src.getAttribute("data-cat"); 134 if (cat) { 135 var c = document.createElement("span"); 136 c.className = "b9-related__cat"; 137 c.textContent = cat; 138 a.appendChild(c); 139 } 140 141 var t = document.createElement("span"); 142 t.className = "b9-related__title"; 143 t.textContent = titleOf(src); 144 a.appendChild(t); 145 grid.appendChild(a); 146 }); 147 148 // dupla desigual (uma com foto, outra sem) fica torta â as duas viram texto 149 if (isFlat(slot.getAttribute("data-readnext-2")) || missing) wrap.classList.add("b9-related--flat"); 150 151 wrap.appendChild(eyebrow); 152 wrap.appendChild(grid); 153 slot.replaceWith(wrap); 154 if (window.b9ApplyQuoteItalics) window.b9ApplyQuoteItalics(wrap); 155 } 156 157 Array.prototype.forEach.call(slots, function (slot) { 158 if (slot.hasAttribute("data-readnext-2")) fillPair(slot); 159 else fillOne(slot); 160 }); 161})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.