PageSourceSearch

https://www.drewno.pl/assets/js/homepage.js?v=1790765823

js drewno.pl collected 2026-10-02 08:02:41 UTC 14,692 bytes, 387 lines download raw bytes

1(function () {
2  'use strict';
3
4  var i18n = window.homepageI18n || {};
5  var cfg  = window.homepageConfig || {};
6
7  /* ─── Pomocnicza - sprawdza czy img ma realny rozmiar ─────── */
8  function imageLooksVisible(img) {
9    var wAttr = parseInt(img.getAttribute('width') || '0', 10);
10    var hAttr = parseInt(img.getAttribute('height') || '0', 10);
11    var w = Math.max(img.clientWidth || 0, img.naturalWidth || 0, isNaN(wAttr) ? 0 : wAttr);
12    var h = Math.max(img.clientHeight || 0, img.naturalHeight || 0, isNaN(hAttr) ? 0 : hAttr);
13    return w > 1 && h > 1;
14  }
15
16  /* ─── Czy kontener reklamowy zawiera widoczną kreację ──────── */
17  function hasRenderableCreative(container) {
18    if (container.querySelector('iframe, object, embed, video')) return true;
19
20    var links = container.querySelectorAll('a[href]');
21    for (var i = 0; i < links.length; i++) {
22      var a = links[i];
23      var href = (a.getAttribute('href') || '').trim();
24      var aText = (a.textContent || '').trim();
25      var aImg = a.querySelector('img');
26      if (href !== '' && aImg && imageLooksVisible(aImg)) return true;
27      if (href !== '' && aText.length > 0) return true;
28    }
29
30    var imgs = container.querySelectorAll('img');
31    for (var j = 0; j < imgs.length; j++) {
32      var img = imgs[j];
33      var inBeacon = !!img.closest('[id^="beacon_"]');
34      if (!inBeacon && imageLooksVisible(img)) return true;
35    }
36
37    return false;
38  }
39
40  /* ─── Czy Revive zwrócił jawny no-fill ─────────────────────── */
41  function isExplicitNoFill(container) {
42    var html = (container.innerHTML || '').toLowerCase();
43    return html.indexOf('bannerid=0') !== -1 || html.indexOf('campaignid=0') !== -1;
44  }
45
46  /**
47   * Po zakończeniu async Revive ustawia na <ins> m.in. data-revive-loaded="1".
48   * Przy braku kreacji w kontenerze traktujemy to jako brak emisji (jak na LB w sekcjach).
49   */
50  function isReviveFinishedWithoutCreative(banner) {
51    var ins = banner.querySelector('ins[data-revive-zoneid]');
52    if (!ins || ins.getAttribute('data-revive-loaded') !== '1') return false;
53    return !hasRenderableCreative(banner);
54  }
55
56  /* Po tym czasie ukrywamy karty nadal bez kreacji (unikamy „pustych” 510px). */
57  var adSlotAuditDeadline = Date.now() + 20000;
58
59  /* ─── Ukrywa puste sloty reklamowe w siatce ────────────────── */
60  function hideEmptyAdSlots() {
61    var slots = document.querySelectorAll('.cards-grid .card-special--ad');
62    if (!slots.length) return;
63
64    var pastAuditDeadline = Date.now() >= adSlotAuditDeadline;
65
66    // FAZA 1: wyłącznie odczyty (pomiary layoutu) - bez żadnych zmian DOM/style
67    var decisions = [];
68    slots.forEach(function (slot) {
69      var banner = slot.querySelector('.card-special__ad-banner');
70      if (!banner) { decisions.push(null); return; }
71      var hasCreative = hasRenderableCreative(banner);
72      var noFill = isExplicitNoFill(banner)
73        || isReviveFinishedWithoutCreative(banner);
74      decisions.push({
75        slot: slot,
76        hasCreative: hasCreative,
77        noFill: noFill,
78        hideAsEmpty: hasCreative ? false : (noFill || pastAuditDeadline),
79      });
80    });
81
82    // FAZA 2: klasa BEM (display w CSS) — bez inline style
83    decisions.forEach(function (d) {
84      if (!d) return;
85      if (d.hideAsEmpty) {
86        d.slot.classList.add('card-special--ad-empty');
87      } else {
88        d.slot.classList.remove('card-special--ad-empty');
89      }
90    });
91    zoneDebugUpdateRuntime();
92  }
93
94  /* ─── Audyt co ~1 s + obserwator DOM (późne wstrzyknięcia Revive) ─ */
95  function scheduleAdSlotAudit() {
96    var runs = 0;
97    var maxRuns = 20;
98    hideEmptyAdSlots();
99    var timer = setInterval(function () {
100      hideEmptyAdSlots();
101      runs++;
102      if (runs >= maxRuns) clearInterval(timer);
103    }, 1000);
104  }
105
106  var cardsGrid = document.querySelector('.cards-grid');
107  if (cardsGrid && typeof MutationObserver !== 'undefined') {
108    var adGridObserver = new MutationObserver(function () {
109      hideEmptyAdSlots();
110    });
111    adGridObserver.observe(cardsGrid, { childList: true, subtree: true });
112  }
113
114  function zoneDebugUpdateRuntime() {
115    if (!window.homepageZoneDebug) return;
116    var rows = document.querySelectorAll('#zone-debug-placements .zone-debug__row');
117    rows.forEach(function (row) {
118      var cell = row.querySelector('.zone-debug__runtime');
119      if (!cell) return;
120      var kind = row.getAttribute('data-zone-debug-row');
121      var msg = '—';
122      if (kind === 'special-ad') {
123        var si = row.getAttribute('data-slot-index');
124        var el = document.querySelector('.cards-grid .card-special--ad[data-slot-index="' + si + '"]');
125        if (!el) {
126          msg = 'brak w DOM';
127        } else if (el.classList.contains('card-special--ad-empty')) {
128          msg = 'ukryta (pusto)';
129        } else {
130          var ban = el.querySelector('.card-special__ad-banner');
131          if (ban && hasRenderableCreative(ban)) msg = 'kreacja w DOM';
132          else {
133            var ins = ban && ban.querySelector('ins[data-revive-zoneid]');
134            if (ins && ins.getAttribute('data-revive-loaded') === '1') msg = 'Revive: brak fill';
135            else msg = 'oczek./ładowanie';
136          }
137        }
138      } else if (kind === 'leaderboard') {
139        var lbi = row.getAttribute('data-lb-index');
140        var lb = document.querySelector('.cards-grid .grid-leaderboard[data-lb-index="' + lbi + '"]');
141        if (!lb) msg = 'brak w DOM';
142        else if (!lb.classList.contains('grid-leaderboard--visible')) msg = 'ukryta';
143        else {
144          var sl = lb.querySelector('.grid-leaderboard__slot');
145          if (sl && hasRenderableCreative(sl) && !isExplicitNoFill(sl)) msg = 'kreacja w DOM';
146          else msg = 'slot pusty / ładowanie';
147        }
148      } else if (kind === 'mobile-b0') {
149        var b0 = document.querySelector('.cards-grid .revive-home-b0');
150        if (!b0) msg = 'brak w DOM';
151        else {
152          var vw = window.innerWidth || 0;
153          if (vw > 680) msg = 'ukryta (viewport > 680px)';
154          else {
155            var b0sl = b0.querySelector('.revive-home-b0__slot');
156            if (b0sl && hasRenderableCreative(b0sl)) msg = 'kreacja w DOM';
157            else {
158              var b0ins = b0sl && b0sl.querySelector('ins[data-revive-zoneid]');
159              if (b0ins && b0ins.getAttribute('data-revive-loaded') === '1') msg = 'Revive: brak fill';
160              else msg = 'oczek./ładowanie';
161            }
162          }
163        }
164      }
165      cell.textContent = msg;
166    });
167  }
168
169  function zoneDebugInit() {
170    if (!window.homepageZoneDebug) return;
171    var panel = document.getElementById('zone-debug-panel');
172    var toggle = document.getElementById('zone-debug-toggle');
173    if (toggle && panel) {
174      toggle.addEventListener('click', function () {
175        var collapsed = panel.classList.toggle('zone-debug--collapsed');
176        toggle.textContent = collapsed ? 'Rozwiń' : 'Zwiń';
177        toggle.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
178      });
179    }
180    zoneDebugUpdateRuntime();
181    var zr = 0;
182    var zt = setInterval(function () {
183      zoneDebugUpdateRuntime();
184      zr++;
185      if (zr >= 25) clearInterval(zt);
186    }, 1000);
187    if (cardsGrid && typeof MutationObserver !== 'undefined') {
188      var zmo = new MutationObserver(function () { zoneDebugUpdateRuntime(); });
189      zmo.observe(cardsGrid, {
190        childList: true,
191        subtree: true,
192        attributes: true,
193        attributeFilter: ['class', 'data-revive-loaded', 'style'],
194      });
195    }
196  }
197
198  /* ─── Audyt pollujący leaderboardów (analogiczny do slotów w sekcjach) ─
199   * Domyślny stan CSS `.grid-leaderboard` to display:none — klasa
200   * `--visible` pokazuje slot. Pokazujemy go DOPIERO po potwierdzeniu
201   * realnej kreacji; dopóki Revive nie skończył, slot zostaje schowany
202   * (brak pustego migotania). Gdy kampania wygasła (Revive skończył bez
203   * kreacji) lub minął deadline — slot pozostaje ukryty. Bez pętli stan
204   * z jednej klatki nigdy nie był rewidowany → pusty slot zostawał. */
205  function auditGridLeaderboards(lbChecks) {
206    if (!lbChecks || !lbChecks.length) { zoneDebugUpdateRuntime(); return; }
207
208    function pass() {
209      var pastDeadline = Date.now() >= adSlotAuditDeadline;
210      var allResolved = true;
211      lbChecks.forEach(function (item) {
212        if (hasRenderableCreative(item.el) && !isExplicitNoFill(item.el)) {
213          item.lb.classList.add('grid-leaderboard--visible');
214          return;
215        }
216        // brak kreacji — chowamy; jeśli to jeszcze nie no-fill i nie po
217        // deadline, rewidujemy w kolejnym cyklu (Revive może domknąć render).
218        item.lb.classList.remove('grid-leaderboard--visible');
219        var resolvedEmpty = isExplicitNoFill(item.el)
220          || isReviveFinishedWithoutCreative(item.el)
221          || pastDeadline;
222        if (!resolvedEmpty) allResolved = false;
223      });
224      zoneDebugUpdateRuntime();
225      return allResolved;
226    }
227
228    if (pass()) return;
229    var runs = 0;
230    var maxRuns = 20;
231    var timer = setInterval(function () {
232      runs++;
233      if (pass() || runs >= maxRuns) clearInterval(timer);
234    }, 1000);
235  }
236
237  /* ─── Leaderboardy (reklamy poziome między kartami) ────────── */
238  function loadLeaderboards(root) {
239    var scope = root || document;
240    var slots = scope.querySelectorAll('.grid-leaderboard .grid-leaderboard__slot[data-lb-zone]');
241    if (!slots.length) return;
242
243    var server = (cfg.reviveServer || '').replace(/\/$/, '');
244    if (!server) return;
245
246    var zones = [], lbMap = {};
247
248    slots.forEach(function (el) {
249      var lb = el.closest('.grid-leaderboard');
250      if (!lb || lb.getAttribute('data-lb-loaded') === '1') return;
251
252      var z = el.getAttribute('data-lb-zone');
253      if (!z || z === '0') return;
254      var seq = zones.length;
255      zones.push(z);
256      lbMap[seq] = el;
257      lb.setAttribute('data-lb-loaded', '1');
258    });
259
260    if (!zones.length) return;
261
262    var url = server + '/delivery/asyncspc.php'
263      + '?zones=' + zones.join('%7C')
264      + '&prefix=lb-'
265      + '&loc=' + encodeURIComponent(location.href)
266      + '&strona=index'
267      + '&urlreg=' + encodeURIComponent(location.pathname)
268      + '&cb=' + Math.floor(Math.random() * 1e9);
269
270    fetch(url)
271      .then(function (r) { return r.json(); })
272      .then(function (data) {
273        // FAZA 1: wszystkie zapisy innerHTML (DOM write)
274        var lbChecks = [];
275        Object.keys(lbMap).forEach(function (seq) {
276          var el = lbMap[seq];
277          var lb = el.closest('.grid-leaderboard');
278          var key = 'lb-' + seq;
279          var d = data[key];
280          if (d && d.html && d.html.indexOf('bannerid=0') === -1) {
281            el.innerHTML = d.html;
282            lbChecks.push({ el: el, lb: lb });
283          } else {
284            lb.classList.remove('grid-leaderboard--visible');
285          }
286        });
287        // FAZA 2: audyt pollujący (jak sloty w sekcjach) — pojedyncza klatka
288        // nie wystarcza: Revive po wygaśnięciu kampanii zwraca wrapper/beacon
289        // bez `bannerid=0`, a obrazkowa kreacja ma chwilowo naturalWidth=0.
290        auditGridLeaderboards(lbChecks);
291      })
292      .catch(function () {
293        Object.keys(lbMap).forEach(function (seq) {
294          var lb = lbMap[seq].closest('.grid-leaderboard');
295          if (lb) lb.classList.remove('grid-leaderboard--visible');
296        });
297      });
298  }
299
300  loadLeaderboards();
301
302  scheduleAdSlotAudit();
303
304  zoneDebugInit();
305
306  /* ─── Load More ─────────────────────────────────────────────── */
307  (function () {
308    var btn  = document.getElementById('load-more-btn');
309    if (!btn) return;
310    var grid = document.querySelector('.cards-grid');
311    if (!grid) return;
312
313    btn.addEventListener('click', function () {
314      var offset   = parseInt(btn.getAttribute('data-offset') || '0', 10);
315      var startPos = parseInt(btn.getAttribute('data-start-pos') || '1', 10);
316      var cardCount = parseInt(btn.getAttribute('data-card-count') || '0', 10);
317      if (isNaN(offset) || offset < 1) return;
318
319      btn.disabled = true;
320      btn.classList.add('loading');
321      btn.textContent = i18n.loading || '';
322
323      var xhr = new XMLHttpRequest();
324      xhr.open('GET', '/?ajax=1&offset=' + offset + '&start_pos=' + startPos + '&card_count_start=' + cardCount);
325
326      xhr.onload = function () {
327        if (xhr.status !== 200) {
328          btn.disabled = false;
329          btn.classList.remove('loading');
330          btn.textContent = i18n.loadMore || '';
331          return;
332        }
333
334        var frag = document.createElement('div');
335        frag.innerHTML = xhr.responseText;
336        var meta  = frag.querySelector('#load-more-meta');
337        var items = frag.querySelectorAll('article, .card-special, .grid-leaderboard');
338        items.forEach(function (el) { grid.appendChild(el); });
339
340        if (window.reviveAsync) {
341          Object.keys(window.reviveAsync).forEach(function (id) {
342            var ra = window.reviveAsync[id];
343            if (ra && typeof ra.dispatchEvent === 'function') ra.dispatchEvent('refresh');
344          });
345        }
346
347        loadLeaderboards(grid);
348        scheduleAdSlotAudit();
349        zoneDebugUpdateRuntime();
350
351        if (meta) {
352          try {
353            var d = JSON.parse(meta.textContent);
354            btn.setAttribute('data-offset', d.nextOffset);
355            btn.setAttribute('data-start-pos', d.nextStartPos);
356            btn.setAttribute('data-card-count', d.nextCardCount);
357            if (!d.hasMore) {
358              if (d.archiveUrl && btn.parentNode) {
359                var archiveLink = document.createElement('a');
360                archiveLink.href = d.archiveUrl;
361                archiveLink.className = 'btn-load-more btn-load-more--archive';
362                archiveLink.textContent = d.archiveLabel || i18n.loadMore || '';
363                btn.parentNode.replaceChild(archiveLink, btn);
364              } else if (btn.parentNode) {
365                btn.parentNode.removeChild(btn);
366              }
367              return;
368            }
369          } catch (e) {}
370        }
371
372        btn.disabled = false;
373        btn.classList.remove('loading');
374        btn.textContent = i18n.loadMore || '';
375      };
376
377      xhr.onerror = function () {
378        btn.disabled = false;
379        btn.classList.remove('loading');
380        btn.textContent = i18n.loadMore || '';
381      };
382
383      xhr.send();
384    });
385  }());
386
387}());

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.