PageSourceSearch

https://www.b9.com.br/assets/js/b9-readnext.js?v=ERUhmcZ03sS9HGyv

js b9.com.br collected 2026-10-02 02:31:11 UTC 5,947 bytes, 161 lines download raw bytes

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.