(function() { const configElement = document.querySelector('script[data-cloudflare-page-counter-config]'); const config = configElement ? JSON.parse(configElement.textContent || '{}') : {}; const endpoint = (config.endpoint || '').replace(/\/$/, ''); const cacheEnabled = config.local_cache !== false; const cachePrefix = `cloudflare-page-counter:${config.site || location.hostname}:`; if (!endpoint) return; const normalizePath = path => { try { const url = new URL(path, location.origin); return decodeURI(url.pathname.replace(/\/index\.html$/, '/')); } catch (error) { return decodeURI(path || location.pathname); } }; const request = payload => { const controller = new AbortController(); const timeout = Number(config.timeout) || 5000; const timer = setTimeout(() => controller.abort(), timeout); return fetch(endpoint, { method : 'POST', headers: { 'Content-Type': 'application/json' }, body : JSON.stringify(payload), credentials: 'omit', signal : controller.signal }).then(response => { clearTimeout(timer); if (!response.ok) throw new Error(`Counter request failed: ${response.status}`); return response.json(); }); }; const render = counts => { document.querySelectorAll('.cloudflare-page-counter').forEach(element => { const path = normalizePath(element.dataset.path); const count = counts[path]; const target = element.querySelector('.cloudflare-page-counter-count'); if (target && typeof count === 'number') target.innerText = count; }); }; const loadCounters = () => { const elements = [...document.querySelectorAll('.cloudflare-page-counter')]; if (!elements.length) return; const entries = elements.map(element => ({ path : normalizePath(element.dataset.path), title: element.dataset.title || document.title })); const hitIndex = elements.findIndex(element => element.dataset.increment === 'true'); let action = hitIndex === -1 ? 'get' : 'hit'; let selectedEntries = entries; if (action === 'hit') { const key = cachePrefix + entries[hitIndex].path; selectedEntries = [entries[hitIndex]]; if (cacheEnabled && localStorage.getItem(key)) { action = 'get'; selectedEntries = entries; } else if (cacheEnabled) { localStorage.setItem(key, String(Date.now())); } } request({ action, site : config.site || location.hostname, entries: selectedEntries }).then(data => { render(data.counts || {}); }).catch(error => { console.error('Cloudflare Page Counter Error', error); }); }; document.addEventListener('DOMContentLoaded', loadCounters); document.addEventListener('page:loaded', loadCounters); })();