(() => { 'use strict'; const root = document.getElementById('stats-studio'); if (!root) return; const status = document.getElementById('studio-status'); const data = document.getElementById('stats-data'); if (!data || typeof Chart === 'undefined') return; const chartData = JSON.parse(data.textContent); const clear = document.getElementById('clear-selection'); const tbody = document.getElementById('evidence-body'); let selectionScope = 'trend'; const original = [...tbody.children].map(row => row.cloneNode(true)); const pagination = root.querySelector('.studio-pagination'); const period = document.getElementById('evidence-period'); const originalPagination = [...pagination.children].map(node => node.cloneNode(true)); let pending = null; clear.onclick = () => { pending?.abort(); period.value = ''; tbody.replaceChildren(...original.map(row => row.cloneNode(true))); pagination.replaceChildren(...originalPagination.map(node => node.cloneNode(true))); clear.hidden = true; document.getElementById('evidence-heading').textContent = `Contributing ${root.dataset.source}`; status.textContent = ''; }; period.onchange = () => { if (period.value) loadBucket(period.value,1,selectionScope); else clear.click(); }; async function loadBucket(bucket, page = 1, scope = 'trend') { selectionScope=scope; pending?.abort(); const controller = new AbortController(); pending = controller; const url = new URL('/stats/runs', location.origin); url.search = new URLSearchParams({query:root.dataset.query,bucket,page,scope}); status.textContent = 'Loading contributing runs…'; try { const response = await fetch(url, {signal:controller.signal}); if (!response.ok) throw new Error(); const result = await response.json(); tbody.replaceChildren(); result.rows.forEach(row => { const tr = document.createElement('tr'); const td = document.createElement('td'); const a = document.createElement('a'); a.href = `/activities/${row.id}`; a.textContent = `${row.title} · ${row.date}`; td.append(a); tr.append(td); if (root.dataset.showPrevious === 'true') { const detail=document.createElement('small');detail.className='previous-run'; detail.append('Previous: '); if(row.previous_run){const previous=document.createElement('a');previous.href=`/activities/${row.previous_run.id}`;previous.textContent=`${row.previous_run.date} · ${row.previous_run.title}`;detail.append(previous);}else detail.append('No earlier recorded run'); td.append(detail); } [`${row.distance} km`, ...row.values].forEach(text => { const cell = document.createElement('td'); cell.textContent = text; tr.append(cell); }); tbody.append(tr); }); document.getElementById('evidence-heading').textContent = `${bucket} · ${result.count} ${root.dataset.source}`; period.value = bucket; pagination.replaceChildren(); const label = document.createElement('span'); label.textContent = `Page ${result.page} of ${result.pages} · selected period`; pagination.append(label); [[result.page > 1, 'Previous', result.page - 1], [result.page < result.pages, 'Next', result.page + 1]].forEach(([show, name, target]) => { if (!show) return; const button = document.createElement('button'); button.type = 'button'; button.className = 'button secondary'; button.textContent = name; button.onclick = () => loadBucket(bucket, target, scope); pagination.append(button); }); clear.hidden = false; status.textContent = 'Selected period loaded.'; } catch (error) { if (error.name !== 'AbortError') status.textContent = 'Could not load this period. Try again.'; } } root.querySelectorAll('[data-bucket]').forEach(button=>button.onclick=()=>loadBucket(button.dataset.bucket,1,'group')); const plots=document.getElementById('analysis-plots'); if(plots)StrideCharts.render(plots,chartData,bucket=>loadBucket(bucket)); const insightPanel=document.getElementById('analysis-insights'); if(insightPanel)StrideCharts.insights(insightPanel,JSON.parse(document.getElementById('insights-data').textContent),bucket=>loadBucket(bucket,1,'group')); const initialBucket=new URL(location.href).searchParams.get('bucket'); if(initialBucket)loadBucket(initialBucket,1,new URL(location.href).searchParams.get('scope')||'trend'); })();