1/* ============================================================ 2 ad-placements.js â CLEAN-ROOM (pagina /teste) 3 Helper para inserir <ad-placement> (custom element do TagBundle) 4 SEM espalhar markup e includes SSI pela pagina. 5 6 Dois modos: 7 1) DECLARATIVO â poe no HTML apenas: 8 <div data-ad="leaderboard-1" data-format="Billboard"></div> 9 e este script expande-o para o <ad-placement> completo. 10 2) IMPERATIVO â RCAds.insert('#alvo', { id:'leaderboard-9', format:'Billboard' }); 11 12 Porque funciona: <ad-placement> e um Web Component do SDK TagBundle; 13 auto-renderiza quando entra no DOM, desde que o SDK ja tenha corrido 14 o .init(). Em dev (.local) o gate NAO chama init, por isso o elemento 15 aparece no DOM mas SEM anuncio â comportamento esperado, nao e bug. 16 17 Atributos data-* suportados no modo declarativo: 18 data-ad (obrigatorio) id do slot -> id + adunit 19 data-format Billboard | Mrec | Halfpage ... -> format (def: Billboard) 20 data-adunit override do adunit (def: BMAP_Comercial/<id>) 21 data-refresh "true"/"false" (def: false) 22 data-lazyload "true"/"false" (def: true) 23 data-targeting string GAM (def: type=premium;obs=123) 24 25 ATENCAO -- NUNCA ESCREVER A TAG ad-placement DENTRO DE UM COMENTARIO HTML 26 ------------------------------------------------------------------------- 27 Escreve-se "ad-placement" em texto, SEM os sinais de maior/menor. 28 Porque: o gerador de paginas estaticas 29 (S:\AutomaticPageGenerationPy, shrink_content e clean_adplacement) limpa o 30 interior dos anuncios renderizados com uma regex do tipo 31 "abre-tag ad-placement ... qualquer coisa ... fecha-tag ad-placement". 32 Essa regex nao sabe o que e um comentario: se o comentario tiver a tag 33 escrita por extenso, o motor arranca ALI e come tudo ate ao fecho do 34 anuncio SEGUINTE -- incluindo o "-->" do proprio comentario. O comentario 35 fica sem fecho e engole o markup a seguir. 36 Foi isso que aconteceu no /noticias: o leaderboard-1 e o out-of-page 37 ficavam DENTRO de um comentario na pagina gerada (out-of-page = 0 38 ocorrencias no HTML final), e a pub "as vezes nao aparecia" -- so os slots 39 mais abaixo na pagina sobreviviam. 40 E a mesma armadilha do tcf-listener.js, noutra forma: ali era o nome da 41 API de consentimento a apagar um script inline, aqui e o nome da tag a 42 apagar markup. Regra geral: nos comentarios nao se escrevem os nomes que 43 o gerador procura. 44 45 RESERVA DE ESPACO DO BILLBOARD DO TOPO (anti layout shift) 46 ------------------------------------------------------------------------- 47 O billboard do topo esta ACIMA do header. Sem altura reservada, o slot 48 media 0px e ao chegar o anuncio empurrava o header e o menu 250px para 49 baixo: quem ia clicar no hamburguer acabava a clicar na pub. Medido na 50 homepage de producao: CLS 0.4693 e o menu de y=80 para y=330. 51 52 A RESERVA NAO ESTA AQUI, DE PROPOSITO. Esta em CSS estatico no global.css 53 (selector div[data-ad="leaderboard-1"], que ja vem no HTML do servidor) e 54 e ligada por um script sincrono no head, no config.xsl. Tentei primeiro 55 faze-la aqui, marcando o elemento por JS, e medi o resultado: ficou PIOR 56 que o bug. O JS so corre depois da primeira pintura, logo a reserva 57 passava a ser ela propria um segundo salto de 250px -- CLS de 0.2847 para 58 0.4622, em todas as cargas, mesmo nas que nao tinham anuncio. 59 Licao: reserva de espaco tem de vir do HTML/CSS da primeira pintura; 60 por JS chega sempre tarde. 61 62 O que sobra para este script e SO o colapso: quando o GAM diz que o slot 63 veio vazio, tira-se o espaco. E por EVENTO, nunca por temporizador -- 64 medi anuncios a chegar aos 941ms mas tambem aos 13897ms, porque a pub 65 espera pelo consentimento do CMP, e um temporizador curto colapsaria o 66 espaco justo a tempo de o anuncio empurrar o header outra vez. 67 O registo vai pelo googletag.cmd, que aceita callbacks antes de o SDK 68 existir; um addEventListener directo perdia os eventos. 69 ============================================================ */ 70(function (w, d) { 71 'use strict'; 72 73 var DEFAULTS = { 74 format: 'Billboard', 75 refresh: 'false', 76 lazyload: 'true', 77 targeting: 'type=premium;obs=123' 78 }; 79 80 // Constroi o elemento <ad-placement> a partir de um objecto de opcoes. 81 function build(opts) { 82 if (!opts || !opts.id) { console.warn('RCAds: falta o "id" do ad'); return null; }
83 var ad = d.createElement('ad-placement'); 84 ad.id = opts.id; 85 ad.setAttribute('adunit', opts.adunit || ('BMAP_Comercial/' + opts.id)); 86 ad.setAttribute('format', opts.format || DEFAULTS.format); 87 ad.setAttribute('refresh', String(opts.refresh != null ? opts.refresh : DEFAULTS.refresh)); 88 89 var lazy = opts.lazyload != null ? opts.lazyload : DEFAULTS.lazyload; 90 if (lazy !== false && lazy !== 'false') ad.setAttribute('lazyload', 'true'); 91 92 var targeting = opts.targeting != null ? opts.targeting : DEFAULTS.targeting; 93 if (targeting) ad.setAttribute('targeting', targeting); 94 95 if (opts.className) ad.className = opts.className; 96 return ad; 97 } 98 99 // Insere um ad dentro de um alvo (selector CSS ou elemento). 100 function insert(target, opts) { 101 var host = typeof target === 'string' ? d.querySelector(target) : target; 102 if (!host) { console.warn('RCAds: alvo nao encontrado ->', target); return null; } 103 var ad = build(opts); 104 if (ad) host.appendChild(ad); 105 return ad; 106 } 107 108 // Expande todos os placeholders [data-ad] da pagina (idempotente). 109 function expand(root) { 110 var scope = root || d; 111 var nodes = scope.querySelectorAll('[data-ad]'); 112 Array.prototype.forEach.call(nodes, function (node) { 113 if (node.getAttribute('data-ad-done') === '1') return; 114 var ad = build({ 115 id: node.getAttribute('data-ad'), 116 format: node.getAttribute('data-format'), 117 adunit: node.getAttribute('data-adunit'), 118 refresh: node.getAttribute('data-refresh'), 119 lazyload: node.getAttribute('data-lazyload'), 120 targeting: node.getAttribute('data-targeting') 121 }); 122 if (ad) { node.appendChild(ad); node.setAttribute('data-ad-done', '1'); } 123 }); 124 } 125 126 // ---------------- colapso do billboard do topo, se vier vazio ---------- 127 128 var ID_TOPO = 'leaderboard-1'; 129 var CLS_VAZIO = 'rc-pub-vazio'; 130 131 // O espaco reservado esta no div[data-ad] do markup (o .text-center), nao 132 // no <ad-placement>: e o div que ocupa o lugar no fluxo, e assim o slot em 133 // si continua a medir o anuncio, sem min-height a mentir sobre a altura. 134 function divDoTopo() { 135 return d.querySelector('div[data-ad="' + ID_TOPO + '"]'); 136 } 137 138 // Colapsa quando o GAM diz que o slot veio vazio, e devolve o espaco se um 139 // refresh trouxer anuncio (o leaderboard-1 tem refresh de 30s). 140 function ouvirGam() { 141 var alvo = divDoTopo(); 142 if (!alvo) return; 143 w.googletag = w.googletag || { cmd: [] }; 144 w.googletag.cmd.push(function () { 145 try { 146 w.googletag.pubads().addEventListener('slotRenderEnded', function (e) { 147 var id; 148 try { id = e.slot.getSlotElementId(); } catch (err) { return; } 149 if (id !== ID_TOPO) return; 150 alvo.classList.toggle(CLS_VAZIO, !!e.isEmpty); 151 }); 152 } catch (err) { 153 console.warn('RCAds: nao consegui ouvir o slotRenderEnded ->', err); 154 } 155 }); 156 } 157 158 function arrancar() { 159 expand(); 160 ouvirGam(); 161 } 162 163 // API publica 164 w.RCAds = { insert: insert, build: build, expand: expand }; 165 166 // Auto-expandir assim que o DOM estiver pronto. 167 if (d.readyState === 'loading') { 168 d.addEventListener('DOMContentLoaded', arrancar); 169 } else { 170 arrancar(); 171 } 172})(window, document);
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.