PageSourceSearch

https://www.noticiastrabajo.es/assets/nt-ads.js?v=20b0521c

js noticiastrabajo.es collected 2026-10-02 04:42:16 UTC 12,034 bytes, 405 lines download raw bytes

1// /assets/nt-ads.js — Publicidad web con Google Ad Manager (GPT). MIG-2.15.
2// Codigo de la guia de implementacion v1.2 de NoticiasTrabajo (24/9/2026, apartado 4.2).
3// Se carga con async despues de gpt.js (GamLoader.astro). En la fase 3 se envolvera
4// aqui Prebid, por eso la definicion de slots queda en una unica funcion.
5// Cambios respecto al codigo de la guia:
6//  - Los slots se definen tras DOMContentLoaded: con gpt.js en cache este script puede
7//    ejecutarse antes de que el parser llegue a los huecos del body.
8//  - El zocalo arranca oculto con visibility:hidden (CSS) y no con display:none: con
9//    display:none el div no pasaba la comprobacion de visibilidad y el slot nunca se
10//    definia. Mientras se ve, el body reserva su altura abajo para no tapar Taboola
11//    ni el pie.
12//  - Key-values, lazy load, colapso, centrado y SRA con setConfig en vez de los metodos
13//    de pubads (setTargeting, enableLazyLoad…), que GPT marca como obsoletos.
14//  - Colapso solo sin relleno (ON_NO_FILL), no antes de pedir el anuncio: ver abajo.
15//    La cabecera (nt-ad-top, nt-ad-top-m) no colapsa nunca, para no provocar CLS.
16//  - La altura del zocalo solo se toma de size si es un array (puede llegar 'fluid').
17//  - Los mid solo piden los formatos de escritorio que caben en el ancho del hueco.
18window.googletag = window.googletag || { cmd: [] };
19googletag.cmd.push(function () {
20  var NET = "/21760474234/noticiastrabajo.es/"; // red + unidad padre
21  var pubads = googletag.pubads();
22
23  function defineSlots() {
24    // Metadatos del dataLayer: page_metadata trae page_type; section, content_type y page_version llegan en un push aparte sin event
25    var meta = {};
26    (window.dataLayer || []).forEach(function (e) {
27      if (
28        e &&
29        (e.event === "page_metadata" ||
30          e.page_type ||
31          e.section ||
32          e.content_type)
33      ) {
34        Object.assign(meta, e);
35      }
36    });
37
38    // Size mappings: [ancho viewport, alto] => tamanos permitidos
39    var mapTop = googletag
40      .sizeMapping()
41      .addSize(
42        [1024, 0],
43        [
44          [970, 250],
45          [970, 90],
46          [728, 90],
47        ],
48      )
49      .addSize([768, 0], [[728, 90]])
50      .addSize(
51        [0, 0],
52        [
53          [320, 100],
54          [320, 50],
55          [300, 100],
56        ],
57      )
58      .build();
59    var mapMpu = googletag
60      .sizeMapping()
61      .addSize(
62        [1024, 0],
63        [
64          [300, 600],
65          [300, 250],
66        ],
67      )
68      .addSize([0, 0], [])
69      .build();
70    var mapSide = googletag
71      .sizeMapping()
72      .addSize(
73        [1024, 0],
74        [
75          [300, 600],
76          [300, 250],
77        ],
78      )
79      .addSize([0, 0], [])
80      .build();
81    var mapIntext = googletag
82      .sizeMapping()
83      .addSize([1024, 0], [[728, 90], [336, 280], [300, 250], "fluid"])
84      .addSize([0, 0], [[300, 600], [336, 280], [300, 250], "fluid"]) // movil: AMP igual pero sin 336x280
85      .build();
86    // intext-2 y 3: sin 300x600, que en estas posiciones paga menos que el 336x280
87    var mapIntextLow = googletag
88      .sizeMapping()
89      .addSize([1024, 0], [[728, 90], [336, 280], [300, 250], "fluid"])
90      .addSize([0, 0], [[336, 280], [300, 250], "fluid"])
91      .build();
92    // Los mid dependen del ancho del hueco, no solo del viewport: en los listados de
93    // seccion la columna mide 628-836 px y un 970 empujaba el lateral fuera de pantalla.
94    // Si no cabe ningun formato de escritorio, se piden los de movil.
95    function mapMid(el) {
96      var width = el.clientWidth;
97      var mobile = [
98        [336, 280],
99        [300, 250],
100      ];
101      var desktop = [
102        [970, 250],
103        [970, 90],
104        [728, 90],
105      ]
106        .filter(function (s) {
107          return s[0] <= width;
108        })
109        .concat(mobile);
110      return googletag
111        .sizeMapping()
112        .addSize([1024, 0], desktop)
113        .addSize([0, 0], mobile)
114        .build();
115    }
116    var mapTopM = googletag
117      .sizeMapping()
118      .addSize([1024, 0], [])
119      .addSize(
120        [0, 0],
121        [
122          [336, 280],
123          [300, 250],
124          [320, 100],
125          [320, 50],
126          [300, 100],
127        ],
128      )
129      .build();
130    var mapSticky = googletag
131      .sizeMapping()
132      .addSize([1024, 0], []) // escritorio: fase 2
133      .addSize(
134        [0, 0],
135        [
136          [320, 100],
137          [320, 50],
138          [300, 100],
139        ],
140      )
141      .build();
142
143    // La cabecera se pide nada mas cargar, a la vista del lector: si colapsara sin
144    // relleno, todo el contenido subiria de golpe (CLS de 0,12 a 0,46 medido en local).
145    // Estos huecos conservan su altura reservada aunque no haya anuncio.
146    var NEVER_COLLAPSE = { "nt-ad-top": true, "nt-ad-top-m": true };
147
148    // Solo se define el slot si el div existe y es visible (display != none)
149    function define(unit, divId, sizes, mapping, pos) {
150      var el = document.getElementById(divId);
151      if (
152        !el ||
153        (el.offsetParent === null && getComputedStyle(el).position !== "fixed")
154      ) {
155        return;
156      }
157      var s = googletag.defineSlot(NET + unit, sizes, divId);
158      if (s) {
159        s.defineSizeMapping(
160          typeof mapping === "function" ? mapping(el) : mapping,
161        ).addService(pubads);
162        s.setConfig({ targeting: { pos: pos } });
163        if (NEVER_COLLAPSE[divId]) {
164          s.setConfig({ collapseDiv: "DISABLED" });
165        }
166      }
167    }
168
169    // Primer argumento: codigo de la unidad en Ad Manager (no el nombre). En 
169web coincide con el id del div.
170    define(
171      "nt-ad-top",
172      "nt-ad-top",
173      [
174        [970, 250],
175        [970, 90],
176        [728, 90],
177        [320, 100],
178        [320, 50],
179        [300, 100],
180      ],
181      mapTop,
182      "top",
183    );
184    define(
185      "nt-ad-top-m",
186      "nt-ad-top-m",
187      [
188        [336, 280],
189        [300, 250],
190        [320, 100],
191        [320, 50],
192        [300, 100],
193      ],
194      mapTopM,
195      "top_m",
196    );
197    define(
198      "nt-ad-mpu-1",
199      "nt-ad-mpu-1",
200      [
201        [300, 600],
202        [300, 250],
203      ],
204      mapMpu,
205      "mpu1",
206    );
207    define(
208      "nt-ad-mpu-2",
209      "nt-ad-mpu-2",
210      [
211        [300, 600],
212        [300, 250],
213      ],
214      mapMpu,
215      "mpu2",
216    );
217    // Lateral de las listas verticales con publi de portada (uno por bloque)
218    document
219      .querySelectorAll('[id^="nt-ad-home-side-"]')
220      .forEach(function (el, i) {
221        define(
222          "nt-ad-home-side",
223          el.id,
224          [
225            [300, 600],
226            [300, 250],
227          ],
228          mapSide,
229          "home_side" + (i + 1),
230        );
231      });
232    define(
233      "nt-ad-intext-1",
234      "nt-ad-intext-1",
235      [[728, 90], [300, 600], [336, 280], [300, 250], "fluid"],
236      mapIntext,
237      "intext1",
238    );
239    define(
240      "nt-ad-intext-2",
241      "nt-ad-intext-2",
242      [[728, 90], [336, 280], [300, 250], "fluid"],
243      mapIntextLow,
244      "intext2",
245    );
246    define(
247      "nt-ad-intext-3",
248      "nt-ad-intext-3",
249      [[728, 90], [336, 280], [300, 250], "fluid"],
250      mapIntextLow,
251      "intext3",
252    );
253    define(
254      "nt-ad-mid-1",
255      "nt-ad-mid-1",
256      [
257        [970, 250],
258        [970, 90],
259        [728, 90],
260        [336, 280],
261        [300, 250],
262      ],
263      mapMid,
264      "mid1",
265    );
266    define(
267      "nt-ad-mid-2",
268      "nt-ad-mid-2",
269      [
270        [970, 250],
271        [970, 90],
272        [728, 90],
273        [336, 280],
274        [300, 250],
275      ],
276      mapMid,
277      "mid2",
278    );
279    define(
280      "nt-ad-sticky",
281      "nt-ad-sticky",
282      [
283        [970, 90],
284        [728, 90],
285        [320, 100],
286        [320, 50],
287        [300, 100],
288      ],
289      mapSticky,
290      "sticky",
291    );
292
293    // Key-values de pagina
294    googletag.setConfig({
295      targeting: {
296        page_type: String(meta.page_type || "other"),
297        section: String(meta.section || ""),
298        content_type: String(meta.content_type || ""),
299        page_version: "canonical",
300      },
301    });
302
303    // Rendimiento. collapseDiv ON_NO_FILL: el hueco conserva su altura reservada hasta la
304    // respuesta y solo colapsa si no hay relleno (collapseEmptyDivs(true) de la guia lo
305    // colapsaba ANTES de pedir el anuncio y anulaba la reserva de espacio contra el CLS).
306    // threadYield ENABLED_ALL_SLOTS: GPT cede el hilo principal entre slots tambien con los
307    // que estan a la vista (por defecto solo con los de fuera). Mejora el INP: el clic en
308    // "Aceptar" del CMP dispara las peticiones que esperaban al consentimiento y bajo de
309    // 200-208 ms a 144 ms de mediana (movil emulado, CPU 4x, portada y articulo).
310    googletag.setConfig({
311      lazyLoad: {
312        fetchMarginPercent: 100,
313        renderMarginPercent: 50,
314        mobileScaling: 2.0,
315      },
316      collapseDiv: "ON_NO_FILL",
317      centering: true,
318      singleRequest: true,
319      threadYield: "ENABLED_ALL_SLOTS",
320    });
321
322    // Zocalo: solo visible si hay relleno; ajusta su altura al tamano servido y reserva
323    // ese espacio al final del body. El boton de cierre (Layout.astro) lo quita del DOM.
324    // Con el refresco solo crece, nunca encoge: si tras un 320x100 llega un 320x50 el
325    // borde de arriba bajaria 50 px y contaria como layout shift (CLS) en cada refresco.
326    pubads.addEventListener("slotRenderEnded", function (ev) {
327      if (ev.slot.getSlotElementId() !== "nt-ad-sticky") {
328        return;
329      }
330      var wrap = document.getElementById("nt-sticky-wrap");
331      if (!wrap) {
332        return;
333      }
334      if (ev.isEmpty) {
335        wrap.style.display = "none";
336        document.body.style.paddingBottom = "";
337        return;
338      }
339      var height = Math.max(
340        (Array.isArray(ev.size) && ev.size[1]) || 50, // size puede ser 'fluid'
341        parseInt(wrap.style.height, 10) || 0,
342      );
343      wrap.style.height = height + "px";
344      wrap.style.visibility = "visible";
345      document.body.style.paddingBottom = (wrap.offsetHeight || height) + "px";
346    });
347
348    // Interstitial de Google (pantalla completa entre paginas). GPT devuelve null si la
349    // pagina no es apta (p. ej. escritorio sin soporte), y entonces no se define.
350    var inter = googletag.defineOutOfPageSlot(
351      NET + "nt-ad-interstitial",
352      googletag.enums.OutOfPageFormat.INTERSTITIAL,
353    );
354    if (inter) {
355      inter
356        .addService(pubads)
357        .setConfig({ targeting: { pos: "interstitial" } });
358    }
359
360    // Refresco del zocalo: 30 s despues de cada impresion visible, con la pestana visible
361    // (si esta oculta, espera a que vuelva) y como maximo 10 veces. El key-value refresh
362    // lleva la cuenta. No se refresca si el lector lo ha cerrado (el boton lo quita del DOM).
363    var NT_REFRESH_MS = 30000;
364    var NT_REFRESH_MAX = 10;
365    var stickyRefreshes = 0;
366    pubads.addEventListener("impressionViewable", function (ev) {
367      var s = ev.slot;
368      if (
369        s.getSlotElementId() !== "nt-ad-sticky" ||
370        stickyRefreshes >= NT_REFRESH_MAX
371      ) {
372        return;
373      }
374      function refresh() {
375        if (!document.getElementById("nt-ad-sticky")) {
376          return;
377        }
378        if (document.visibilityState !== "visible") {
379          document.addEventListener("visibilitychange", refresh, {
380            once: true,
381          });
382          return;
383        }
384        stickyRefreshes++;
385        s.setConfig({ targeting: { refresh: String(stickyRefreshes) } });
386        pubads.refresh([s]);
387      }
388      setTimeout(refresh, NT_REFRESH_MS);
389    });
390
391    googletag.enableServices();
392
393    // display() de todos los huecos presentes, interstitial incluido (no hace falta script
394    // inline junto a cada div). Se pasa el slot y no el id: el interstitial no tiene div.
395    pubads.getSlots().forEach(function (s) {
396      googletag.display(s);
397    });
398  }
399
400  if (document.readyState === "loading") {
401    document.addEventListener("DOMContentLoaded", defineSlots);
402  } else {
403    defineSlots();
404  }
405});

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.