/* ags 92 – B2B: filter dostupnosti + „skladom najprv" v zoznamoch produktov (SK/CZ/HU/PL/EN) * Súbor: /buxus/docs/skladom5.js.txt · verzia 2026-10-15f * Nastavenie (riadok pred skriptom v Container 22 Content after): * window.agsSkladom = { mode: 'preview', allow: ['Fiktívna firma pre OZ'], def: 'sklad', markets: ['sk','cz','hu'] }; * mode: 'preview' (len účty z allow) | 'live' (všetci prihlásení) | 'off' * def: predvolený výber pri prvej návšteve: 'all' | 'sklad' | 'cesta' | 'bez' * Čo robí: * - nad každým zoznamom produktov (kategória, značka, vyhľadávanie, kampaň, výpredaj) pridá prepínač * Všetko · Skladom · Na ceste · Bez termínu; voľbu si pamätá (localStorage ags_skl_f). * - „Všetko": preusporiada kartičky na zobrazenej strane – skladom, potom s termínom (od najbližšieho), potom bez termínu. * - Filter: zobrazí len vyhovujúce kartičky; keď ich je na strane málo, dočíta ďalšie produkty zo zoznamu na pozadí * (1 požiadavka = 96 produktov, automaticky najviac 1), tlačidlo „Zobraziť ďalšie" pokračuje (opäť najviac 1 dávka). * - Bez počtov na tlačidlách (prehliadač pozná len načítanú časť zoznamu). * - Stav berie z kartičky (žltý riadok = nie je skladom; dátum v ňom = na ceste). Ceny partnera dočíta len pre viditeľné * dočítané kartičky (API webu, po 2 naraz); naraz ukáže najviac toľko kartičiek, koľko je nastavené na stranu. * - Iba zobrazenie. Nič neukladá na server, nemení košík ani nastavenie počtu položiek. */ (function () { 'use strict'; if (window.__agsSkladomLoaded) { return; } window.__agsSkladomLoaded = true; var VER = '2026-10-15f'; var CFG = window.agsSkladom || {}; var MODE = CFG.mode || 'preview'; if (MODE === 'off') { return; } var ALLOW = CFG.allow || ['Fiktívna firma pre OZ']; var MARKETS = CFG.markets || ['sk', 'cz', 'hu']; var DEF = CFG.def || 'all'; var CHUNK = 96, MAX_CHUNKS = 1; /* automaticky najviac 1 dávka; ďalšie len po kliknutí partnera */ var LS_KEY = 'ags_skl_f'; var m = (location.pathname.match(/^\/(sk|cz|hu|pl|com|en)(\/|$)/i) || [])[1]; m = m ? m.toLowerCase() : 'sk'; if (m === 'com') { m = 'en'; } if (MARKETS.indexOf(m) < 0) { return; } var T = { sk: { lbl: 'Dostupnosť:', all: 'Všetko', sklad: 'Skladom', cesta: 'Na ceste', bez: 'Bez termínu', page: 'na tejto strane', more: 'Zobraziť ďalšie', loading: 'Hľadám ďalšie produkty…', scanned: 'Prehľadaných {n} produktov', done: 'Prehľadaný celý zoznam', none: 'V tomto výbere nie sú žiadne produkty.', sorted: 'Zoradené: skladom najprv', prev: 'NÁHĽAD' }, cz: { lbl: 'Dostupnost:', all: 'Vše', sklad: 'Skladem', cesta: 'Na cestě', bez: 'Bez termínu', page: 'na této stránce', more: 'Zobrazit další', loading: 'Hledám další produkty…', scanned: 'Prohledáno {n} produktů', done: 'Prohledán celý seznam', none: 'V tomto výběru nejsou žádné produkty.', sorted: 'Seřazeno: skladem nejdřív', prev: 'NÁHLED' }, hu: { lbl: 'Elérhetőség:', all: 'Összes', sklad: 'Raktáron', cesta: 'Úton', bez: 'Nincs szállítási idő', page: 'ezen az oldalon', more: 'Továbbiak', loading: 'További termékek keresése…', scanned: '{n} termék átnézve', done: 'A teljes lista átnézve', none: 'Ebben a szűrésben nincs termék.', sorted: 'Rendezés: raktáron lévők elöl', prev: 'ELŐNÉZET' }, pl: { lbl: 'Dostępność:', all: 'Wszystkie', sklad: 'Na stanie', cesta: 'W drodze', bez: 'Bez terminu', page: 'na tej stronie', more: 'Pokaż więcej', loading: 'Szukam kolejnych produktów…', scanned: 'Przejrzano {n} produktów', done: 'Przejrzano całą listę', none: 'Brak produktów w tym wyborze.', sorted: 'Sortowanie: najpierw na stanie', prev: 'PODGLĄD' }, en: { lbl: 'Availability:', all: 'All', sklad: 'In stock', cesta: 'On the way', bez: 'No delivery date', page: 'on this page', more: 'Show more', loading: 'Looking for more products…', scanned: '{n} products checked', done: 'Whole list checked', none: 'No products in this selection.', sorted: 'Sorted: in stock first', prev: 'PREVIEW' } }[m]; function txt(s) { return (s || '').replace(/\s+/g, ' ').trim(); } function lsGet(k) { try { return localStorage.getItem(k); } catch (e) { return null; } } function lsSet(k, v) { try { localStorage.setItem(k, v); } catch (e) {} } function track(ev, data) { try { (window.dataLayer = window.dataLayer || []).push(Object.assign({ event: ev, ags_skl_trh: m }, data || {})); } catch (e) {} } function firmName() { var h = document.querySelector('.header-basic-info h3'); return h ? txt(h.textContent) : ''; } function allowed() { var f = firmName(); if (!f) { return false; } if (MODE === 'live') { return true; } for (var i = 0; i < ALLOW.length; i++) { if (f.toLowerCase().indexOf(String(ALLOW[i]).toLowerCase()) >= 0) { return true; } } return false; } /* ---- stav kartičky ---- */ function parseDate(s) { var a = s.match(/(\d{4})\s*\.\s*(\d{1,2})\s*\.\s*(\d{1,2})/); /* 2026. 10. 05 (HU) */ if (a) { return new Date(+a[1], +a[2] - 1, +a[3]).getTime(); } var b = s.match(/(\d{1,2})\s*\.\s*(\d{1,2})\s*\.\s*(\d{4})/); /* 1.11.2026 */ if (b) { return new Date(+b[3], +b[2] - 1, +b[1]).getTime(); } var c = s.match(/(\d{4})-(\d{2})-(\d{2})/); if (c) { return new Date(+c[1], +c[2] - 1, +c[3]).getTime(); } return null; } function status(card) { if (card.__aggSt) { return card.__aggSt; } var y = card.querySelector('.yellow-background'); var st; if (!y) { st = { k: 'sklad', d: 0 }; } else { var d = parseDate(txt(y.textContent)); st = d ? { k: 'cesta', d: d } : { k: 'bez', d: 0 }; } card.__aggSt = st; return st; } var RANK = { sklad: 0, cesta: 1, bez: 2 }; function cmp(a, b) { var sa = status(a.card), sb = status(b.card); if (RANK[sa.k] !== RANK[sb.k]) { return RANK[sa.k] - RANK[sb.k]; } if (sa.k === 'cesta' && sa.d !== sb.d) { return sa.d - sb.d; } return a.i - b.i; } /* ---- DOM zoznamu ---- */ function grid() { var c = document.querySelector('.row.eq-height .product-card'); return c ? c.closest('.row.eq-height') : null; } function items(g) { var out = []; var ch = g.children; for (var i = 0; i < ch.length; i++) { var card = ch[i].querySelector('.product-card'); if (card) { out.push({ el: ch[i], card: card, i: i }); } } return out; } function isListing() { return !!(grid() && document.querySelector('.fs_results_count, .pagination')); } /* ---- štýl ---- */ function css() { if (document.getElementById('ags-skl-css')) { return; } var s = document.createElement('style'); s.id = 'ags-skl-css'; s.textContent = '#ags-skl{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:4px 0 14px;padding:10px 12px;background:#fff;border:1px solid #d6e6f2;border-radius:6px;font-size:13px}' + '#ags-skl .lbl{font-weight:700;color:#1b3a57;margin-right:2px}' + '#ags-skl button{border:1px solid #1c84c6;background:#fff;color:#1c84c6;border-radius:16px;padding:5px 12px;font-weight:600;cursor:pointer;line-height:1.2}' + '#ags-skl button.on{background:#1c84c6;color:#fff}' + '#ags-skl button[data-f=sklad]:not(.on){border-color:#2e9e5b;color:#237a46}' + '#ags-skl button[data-f=sklad].on{background:#2e9e5b;border-color:#2e9e5b}' + '#ags-skl .info{color:#5a6b7b;margin-left:auto;font-size:12px}' + '#ags-skl .prev{background:#f0ad4e;color:#fff;border-radius:3px;padding:1px 6px;font-size:10px;font-weight:700}' + '#ags-skl-more{display:block;margin:6px auto 22px;border:1px solid #1c84c6;background:#1c84c6;color:#fff;border-radius:4px;padding:9px 22px;font-weight:700;cursor:pointer}' + '#ags-skl-more[disabled]{opacity:.6;cursor:default}' + '#ags-skl-msg{text-align:center;color:#5a6b7b;margin:4px 0 20px}' + '.ags-skl-hide{display:none!important}'; document.head.appendChild(s); } /* ---- stav prepínača ---- */ var filter = lsGet(LS_KEY) || DEF; if (!/^(all|sklad|cesta|bez)$/.test(filter)) { filter = 'all'; } var run = 0; /* poradové číslo behu – zruší staré načítavanie po zmene */ var state = null; /* stav dočítavania pre aktuálny zoznam */ function bar(g) { var b = document.getElementById('ags-skl'); if (b && b.nextElementSibling === g) { return b; } if (b) { b.parentNode.removeChild(b); } b = document.createElement('div'); b.id = 'ags-skl'; b.innerHTML = '' + T.lbl + '' + ['all', 'sklad', 'cesta', 'bez'].map(function (k) { return ''; }).join('') + '' + (MODE === 'preview' ? ' ' + T.prev + '' : ''); g.parentNode.insertBefore(b, g); b.addEventListener('click', function (e) { var t = e.target.closest('button[data-f]'); if (!t) { return; } var f = t.getAttribute('data-f'); if (f === filter && f === 'all') { return; } filter = f; lsSet(LS_KEY, f); track('ags_skl_filter', { ags_skl_f: f }); apply(true); }); return b; } /* bez počtov: prehliadač pozná len načítanú časť zoznamu, číslo by klamalo (rozhodnutie Petra 15. 10.) */ function paint(b, info) { var btns = b.querySelectorAll('button[data-f]'); for (var i = 0; i < btns.length; i++) { btns[i].classList.toggle('on', btns[i].getAttribute('data-f') === filter); } b.querySelector('.info').textContent = info || ''; } function nativePager(show) { var els = document.querySelectorAll('.pagination'); for (var i = 0; i < els.length; i++) { var w = els[i].closest('.row') || els[i]; if (w.contains(grid())) { w = els[i]; } w.classList.toggle('ags-skl-hide', !show); } } function clearExtras() { ['ags-skl-more', 'ags-skl-msg'].forEach(function (id) { var e = document.getElementById(id); if (e) { e.parentNode.removeChild(e); } }); } /* ---- hlavná logika ---- */ var applying = false; function apply(userClick) { var g = grid(); if (!g) { return; } applying = true; run++; var b = bar(g); var list = items(g); if (filter === 'all') { /* návrat po filtri: ak sú v zozname dočítané kartičky, obnovíme pôvodnú stranu */ if (state && state.orig && state.g === g) { g.innerHTML = state.orig; state = null; list = items(g); list.forEach(function (it) { it.card.__agsOwn = true; }); } list.forEach(function (it) { it.el.classList.remove('ags-skl-hide'); }); list.slice().sort(cmp).forEach(function (it) { it.el.__agsSeen = true; g.appendChild(it.el); }); clearExtras(); nativePager(true); paint(b, T.sorted + ' · ' + T.page); applying = false; prices(); return; } /* filter: zoznam prevezmeme od začiatku, aby sa nič nepreskočilo */ if (!state || state.g !== g || state.href !== location.href) { state = { g: g, href: location.href, orig: g.innerHTML, page: 0, end: false, seen: {}, scanned: 0, target: 0 }; list.forEach(function (it) { state.seen[it.card.getAttribute('data-lazy-product-id')] = 1; }); } state.target = perPage(); list.slice().sort(cmp).forEach(function (it) { it.el.__agsSeen = true; g.appendChild(it.el); }); nativePager(false); var vis = show(); applying = false; if (vis < state.target && !state.end) { loadMore(); } else { moreButton(); } } /* zobrazí najviac state.target vyhovujúcich kartičiek (ostatné načítané čakajú skryté na „Zobraziť ďalšie“) */ function show() { var g = grid(); if (!g || !state) { return 0; } var n = 0, list = items(g); list.forEach(function (it) { var on = status(it.card).k === filter && n < state.target; if (on) { n++; } it.el.classList.toggle('ags-skl-hide', !on); }); paint(document.getElementById('ags-skl'), ''); prices(); return n; } function matching() { var g = grid(); return g ? items(g).filter(function (it) { return status(it.card).k === filter; }).length : 0; } function perPage() { /* aktívny počet je jediné číslo v .fs_results_count, ktoré nie je odkaz */ var box = document.querySelector('.fs_results_count'); if (box) { var w = document.createTreeWalker(box, NodeFilter.SHOW_TEXT, null, false), n; while ((n = w.nextNode())) { if (n.parentElement.closest('a')) { continue; } var mm = txt(n.textContent).match(/\b(12|24|48|96)\b/); if (mm) { return +mm[1]; } } } return 24; } function chunkUrl(p) { var u = new URL(location.href); u.searchParams.delete('page'); u.searchParams.set('results_per_page', String(CHUNK)); // BUXUS FS: 1. strana = BEZ parametra page (page=1 vráti chybný výsek, overené 15. 10.) if (p > 1) { u.searchParams.set('page', String(p)); } u.hash = ''; return u.toString(); } function moreButton(loading) { var g = grid(); if (!g || !state) { return; } var btn = document.getElementById('ags-skl-more'); var msg = document.getElementById('ags-skl-msg'); if (!msg) { msg = document.createElement('div'); msg.id = 'ags-skl-msg'; g.parentNode.insertBefore(msg, g.nextSibling); } if (!btn) { btn = document.createElement('button'); btn.id = 'ags-skl-more'; btn.type = 'button'; btn.addEventListener('click', function () { if (!state || btn.disabled) { return; } track('ags_skl_more', { ags_skl_f: filter }); state.target += perPage(); var vis = show(); if (vis < state.target && !state.end) { loadMore(); } else { moreButton(); } }); msg.parentNode.insertBefore(btn, msg); } var visible = items(g).filter(function (it) { return !it.el.classList.contains('ags-skl-hide'); }).length; var waiting = matching() - visible; btn.textContent = loading ? T.loading : T.more; btn.disabled = !!loading; btn.style.display = (!loading && state.end && waiting <= 0) ? 'none' : ''; msg.textContent = (visible === 0 && state.end) ? T.none : ''; } function loadMore() { var myRun = run; var g = grid(); if (!g || !state || state.end) { moreButton(); return; } var chunks = 0; moreButton(true); (function next() { if (myRun !== run || !state) { return; } if (matching() >= state.target || chunks >= MAX_CHUNKS || state.end) { done(); return; } state.page++; chunks++; fetch(chunkUrl(state.page), { credentials: 'same-origin' }) .then(function (r) { return r.text(); }) .then(function (h) { if (myRun !== run || !state) { return; } var d = new DOMParser().parseFromString(h, 'text/html'); var cards = d.querySelectorAll('.row.eq-height .product-card'); if (!cards.length) { state.end = true; next(); return; } state.scanned = (state.page - 1) * CHUNK + cards.length; if (cards.length < CHUNK) { state.end = true; } for (var i = 0; i < cards.length; i++) { var id = cards[i].getAttribute('data-lazy-product-id'); if (state.seen[id]) { continue; } state.seen[id] = 1; var wrap = cards[i].closest('.item') || cards[i].parentElement; var node = document.importNode(wrap, true); node.classList.add('ags-skl-hide'); node.__agsSeen = true; node.querySelector('.product-card').__agsOwn = true; g.appendChild(node); } show(); next(); }) .catch(function () { if (state) { state.end = true; } done(); }); })(); function done() { if (myRun === run) { show(); moreButton(false); } } } /* ceny partnera v dočítaných kartičkách: rovnaké API ako web (/{trh}/api/product/{id}), ale len pre VIDITEĽNÉ kartičky, ktoré pridal tento skript, postupne po 2 (server spracúva požiadavky jednej relácie za sebou – hromadné volanie by zdržalo aj pridanie do košíka). */ var pq = [], pActive = 0, P_PAR = 2; var DOM_SEG = location.pathname.split('/')[1] || 'sk'; function prices() { var g = grid(); if (!g) { return; } items(g).forEach(function (it) { var c = it.card; if (!c.__agsOwn || c.__agsReq || it.el.classList.contains('ags-skl-hide')) { return; } if (!c.querySelector('[data-lazy-property]')) { return; } c.__agsReq = true; pq.push(c); }); pump(); } function pump() { while (pActive < P_PAR && pq.length) { var c = pq.shift(); if (!c.isConnected || (c.closest('.item') && c.closest('.item').classList.contains('ags-skl-hide'))) { c.__agsReq = false; continue; } pActive++; (function (c) { fetch('/' + DOM_SEG + '/api/product/' + encodeURIComponent(c.getAttribute('data-lazy-product-id')), { credentials: 'same-origin' }) .then(function (r) { return r.json(); }) .then(function (data) { var props = c.querySelectorAll('[data-lazy-property]'); for (var i = 0; i < props.length; i++) { var v = data[props[i].getAttribute('data-lazy-property')]; if (v === undefined) { continue; } var t = document.createElement('template'); t.innerHTML = String(v); props[i].replaceWith(t.content); } }) .catch(function () { c.__agsReq = false; }) .then(function () { pActive--; pump(); }); })(c); } } /* ---- štart + sledovanie AJAX zmien (filter kategórie/výrobcu, stránkovanie) ---- */ function start() { if (!allowed() || !isListing()) { return; } css(); apply(false); var host = grid().parentNode; var mo = new MutationObserver(function () { if (applying) { return; } var g = grid(); if (!g) { return; } /* FS (AJAX stránkovanie, filter výrobcu, zoradenie) vymení kartičky v tom istom kontajneri → nové kartičky nemajú značku */ var fresh = false; for (var i = 0; i < g.children.length; i++) { if (!g.children[i].__agsSeen && g.children[i].querySelector('.product-card')) { fresh = true; break; } } if (fresh || !document.getElementById('ags-skl') || document.getElementById('ags-skl').nextElementSibling !== g || (state && state.g !== g)) { state = null; clearTimeout(start.t); start.t = setTimeout(function () { apply(false); }, 80); } }); mo.observe(host.parentNode || host, { childList: true, subtree: true }); track('ags_skl_view', { ags_skl_f: filter }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } window.agsSkladomInfo = { ver: VER, market: m, mode: MODE }; })();