PageSourceSearch

https://www.polskieforumrodzicow.pl/portal/articles-loader.js?v=35

js polskieforumrodzicow.pl collected 2026-10-05 08:16:06 UTC 9,051 bytes, 57 lines download raw bytes

1/* Homepage article rendering. SSR supplies only the hero/header state; the
2   remaining editorial lists continue to use their paginated public endpoints. */
3!function(){
4const API="/api",FALLBACK="/portal/img/placeholder.webp";
5const LABEL={aktualnosci:"Aktualności",wychowanie:"Wychowanie",edukacja:"Edukacja",zdrowie:"Zdrowie",zagrozenia:"Zagrożenia",nauka:"Nauka",rozmowy:"Rozmowy","forum-rodzicow":"Forum Rodziców","rodzinna-tarcza":"Rodzinna Tarcza"};
6const TOPICS=["wychowanie","edukacja","zdrowie","zagrozenia","nauka","rozmowy"];
7let category="all",tag="",offset=0,total=0,loading=false;
8function esc(v){return v==null?"":String(v).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}
9function image(url,w){if(!url)return FALLBACK;if(url.startsWith("/api/storage/public-objects/")||url.startsWith("/api/storage/objects/"))return/[?&]w=/.test(url)?url:url+(url.includes("?")?"&":"?")+"w="+w;return url.startsWith("/")?url:"/api/img?url="+encodeURIComponent(url)+"&w="+w}
10function href(a){return a.sourcePath||a.slug&&a.category?`/${a.category}/${a.slug}`:`/article?id=${encodeURIComponent(a.id||"")}`}
11function date(v,short){try{return new Date(v).toLocaleDateString("pl-PL",{day:"numeric",month:short?"short":"long",year:"numeric"})}catch{return""}}
12function card(a){let cat=a.category||"";return`<article class="article-card" data-cat="${esc(cat)}" data-id="${esc(a.id)}"><div class="card-img-wrap"><a href="${esc(href(a))}" class="card-img-link"><img src="${esc(image(a.imageUrl,500))}" alt="${esc(a.title)}" loading="lazy" width="500" height="334"><span class="cat-badge cat-${esc(cat)}">${esc(LABEL[cat]||cat)}</span></a></div><div class="card-body"><h3 class="card-title"><a href="${esc(href(a))}">${esc(a.title)}</a></h3><p class="card-excerpt">${esc(a.excerpt||"")}</p><div class="card-meta"><time>${date(a.publishedAt||a.createdAt)}</time><span class="read-time">${a.readingTimeMinutes||5} min</span></div></div></article>`}
13function renderHero(hero,sides){
14 const main=document.querySelector(".hero-grid .hero-main"),side=document.querySelector(".hero-grid .hero-side");if(!hero)return;
15 if(main&&!window.__PFR_SSR__)main.innerHTML=`<a href="${esc(href(hero))}" class="hero-main-link"><div class="hero-img-wrap"><img src="${esc(image(hero.imageUrl,900))}" alt="${esc(hero.title)}" loading="eager" fetchpriority="high" decoding="async" width="900" height="600"><div class="hero-overlay"></div></div><div class="hero-content"><span class="cat-badge cat-${esc(hero.category||"")}">${esc(LABEL[hero.category]||hero.category||"")}</span><h2 class="hero-title">${esc(hero.title)}</h2><div class="hero-meta"><span class="author-name">${esc(hero.author||"Redakcja PFR")}</span><span class="meta-sep">·</span><time>${date(hero.publishedAt||hero.createdAt)}</time></div></div></a>`;
16 if(side)side.innerHTML=(sides||[]).filter(Boolean).slice(0,4).map(a=>`<article class="side-card"><a href="${esc(href(a))}" style="display:contents"><img src="${esc(image(a.imageUrl,200))}" alt="${esc(a.title)}" loading="lazy" width="200" height="133"><div class="side-card-body"><div class="side-card-meta"><span class="cat-badge cat-${esc(a.category||"")}">${esc(LABEL[a.category]||a.category||"")}</span><time>${date(a.publishedAt||a.createdAt)}</time></div><h3><span class="side-card-title">${esc(a.title)}</span></h3></div></a></article>`).join("");
17}
18async function request(path){const r=await fetch(API+path);if(!r.ok)throw Error("API "+r.status);return r.json()}
19async function renderTopics(){
20 await Promise.all(TOPICS.map(async cat=>{const el=document.querySelector(`[data-topic-cat="${cat}"]`);if(!el)return;try{const data=await request(`/articles?published=true&limit=6&category=${encodeURIComponent(cat)}`),arts=data.articles||[];if(!arts.length){el.innerHTML="";return}const first=arts[0],rest=arts.slice(1);el.innerHTML=`<a href="${esc(href(first))}" class="topic-featured"><div class="topic-featured-img"><img src="${esc(image(first.imageUrl,600))}" alt="${esc(first.title)}" loading="lazy" width="600" height="400"><span class="topic-featured-cat cat-${esc(cat)}">${esc(LABEL[cat]||cat)}</span></div><div class="topic-featured-body"><p class="topic-featured-title">${esc(first.title)}</p><time>${date(first.publishedAt||first.createdAt,true)}</time></div></a>${rest.length?`<ul class="topic-list topic-list-img">${rest.map(a=>`<li><a href="${esc(href(a))}" class="topic-item-img"><img src="${esc(image(a.imageUrl,120))}" alt="" loading="lazy" width="120" height="90"><div class="topic-item-text"><span>${esc(a.title)}</span><time>${date(a.publishedAt||a.createdAt,true)}</time></div></a></li>`).join("")}</ul>`:""}`;}catch{el.innerHTML=""}}));
21}
22async function renderPopular(){
23 const el=document.querySelector(".popular-list");if(!el)return;
24 try{
25  const arts=await request("/articles/top?limit=6");
26  if(!Array.isArray(arts)||!arts.length){el.innerHTML='<li class="popular-item" style="color:#888;padding:.75rem">Brak artykułów.</li>';return}
27  el.innerHTML=arts.map(a=>{const cat=a.category||"";return`<li class="popular-item"><a href="${esc(href(a))}" class="popular-link"><div class="popular-thumb"><img src="${esc(image(a.imageUrl,120))}" alt="" loading="lazy" width="120" height="90" onerror="this.src='${FALLBACK}'"></div><div class="popular-text"><div class="popular-meta-row"><span class="popular-cat cat-${esc(cat)}"><span class="popular-cat-dash"></span>${esc(LABEL[cat]||cat)}</span><time class="popular-date">${date(a.publishedAt||a.createdAt,true)}</time></div><p>${esc(a.title)}</p></div></a></li>`}).join("");
28 }catch(e){
29  console.error("Błąd ładowania najczęściej czytanych:",e);
30  el.innerHTML='<li class="popular-item" style="color:#888;padding:.75rem">Nie udało się załadować artykułów.</li>';
31 }
32}
33async function renderSponsored(){
34 const el=document.getElementById("sponsored-grid");if(!el)return;
35 try{
36  const data=await request("/articles?published=true&limit=8&category=material-sponsorowany&sort=date&dir=desc"),arts=(data.articles||[]).slice(0,8);
37  if(!arts.length){el.innerHTML='<p style="grid-column:1/-1;color:#888;padding:1rem 0">Brak artykułów sponsorowanych.</p>';return}
38  el.innerHTML=arts.map(a=>`<a href="${esc(href(a))}" class="sponsored-card"><div class="sponsored-card-img"><img src="${esc(image(a.imageUrl,400))}" alt="${esc(a.title)}" loading="lazy" width="400" height="250" onerror="this.src='${FALLBACK}'"><span class="sponsored-badge">Sponsorowane</span></div><div class="sponsored-card-body"><p class="sponsored-card-title">${esc(a.title)}</p></div></a>`).join("");
39 }catch(e){
40  console.error("Błąd ładowania artykułów sponsorowanych:",e);
41  el.innerHTML='<p style="grid-column:1/-1;color:#888;padding:1rem 0">Nie udało się załadować artykułów sponsorowanych.</p>';
42 }
43}
44function updateMore(){const wrap=document.querySelector(".load-more-wrap"),more=document.getElementById("btn-load-more"),all=document.getElementById("btn-load-all");if(wrap)wrap.style.display=offset<total?"flex":"none";if(more)more.disabled=loading;if(all)all.disabled=loading}
45async function loadGrid(replace){
46 if(loading)return;loading=true;updateMore();try{let data;if(category==="all"&&!tag){data=await request("/articles?published=true&limit=6&offset="+offset)}else data=await request(`/articles?published=true&limit=6&offset=${offset}&${tag?"tag="+encodeURIComponent(tag):"category="+encodeURIComponent(category)}`);const arts=data.articles||[],grid=document.getElementById("articles-grid");total=data.total||0;if(grid){if(replace)grid.innerHTML=arts.map(card).join("")||'<p style="grid-column:1/-1;text-align:center;color:#666;padding:2rem">Brak artykułów.</p>';else grid.insertAdjacentHTML("beforeend",arts.map(card).join(""))}offset+=arts.length;}catch(e){console.error("Błąd ładowania artykułów:",e)}finally{loading=false;updateMore()}}
47async function init(){
48 let header=null;
49 if(window.__PFR_SSR__&&window.__PFR_SSR__.topHeader)header=window.__PFR_SSR__.topHeader;
50 else try{header=await request("/site-settings/top-header")}catch{}
51 if(header){let hero=header.hero,sides=header.sides;if(!hero)try{const latest=await request("/articles?published=true&limit=5");hero=(latest.articles||[])[0];sides=(latest.articles||[]).slice(1)}catch{}renderHero(hero,sides)}
52 await Promise.all([loadGrid(true),renderTopics(),renderPopular(),renderSponsored()]);
53 const more=document.getElementById("btn-load-more"),all=document.getElementById("btn-load-all");if(more)more.addEventListener("click",()=>loadGrid(false));if(all)all.addEventListener("click",async()=>{while(offset<total&&!loading)await loadGrid(false)});
54 document.addEventListener("click",e=>{const b=e.target.closest(".cat-tab");if(!b)return;e.preventDefault();document.querySelectorAll(".cat-tab").forEach(x=>x.classList.remove("active"));b.classList.add("active");category=b.dataset.cat||"all";tag=b.dataset.tag||"";offset=0;total=0;loadGrid(true)},true);
55}
56if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",init);else init();
57}();

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.