Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions fossils/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,12 @@ <h3>📖 About The Fossil Record</h3>
});
}

function escapeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}

function showTooltip(event, d) {
const archConfig = ARCHITECTURES[d.arch] || { label: d.arch };

Expand All @@ -849,7 +855,7 @@ <h3>📖 About The Fossil Record</h3>
html += `
<div class="tooltip-row" style="margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.1);">
<span class="tooltip-label" style="display: block; margin-bottom: 5px;">Sample Miners:</span>
<span class="tooltip-value" style="display: block; font-size: 0.8rem;">${sampleMiners.join(', ')}</span>
<span class="tooltip-value" style="display: block; font-size: 0.8rem;">${escapeHtml(sampleMiners.join(', '))}</span>
</div>
`;
}
Expand Down Expand Up @@ -915,7 +921,7 @@ <h3>📖 About The Fossil Record</h3>
const container = d3.select('#visualization');
container.html(`
<div class="error-message">
<strong>Error loading data:</strong> ${message}
<strong>Error loading data:</strong> ${escapeHtml(message)}
<br><br>
<button onclick="location.reload()">Retry</button>
<button class="secondary" onclick="document.dispatchEvent(new CustomEvent('loadSampleData'))">
Expand Down
14 changes: 10 additions & 4 deletions visualizations/fossil-record.html
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ <h1>⛏ The Fossil Record — RustChain Attestation Archaeology</h1>
};

let currentRange = 'all';
function escapeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}

let visibleArchs = new Set(ARCHS.map(a => a.name));

function getFilteredData() {
Expand All @@ -209,7 +215,7 @@ <h1>⛏ The Fossil Record — RustChain Attestation Archaeology</h1>
const item = document.createElement('div');
item.className = 'legend-item';
item.dataset.arch = a.name;
item.innerHTML = `<div class="legend-swatch" style="background:${a.color}"></div>${a.name}`;
item.innerHTML = `<div class="legend-swatch" style="background:${escapeHtml(a.color)}"></div>${escapeHtml(a.name)}`;
item.addEventListener('click', () => {
if (visibleArchs.has(a.name)) {
if (visibleArchs.size > 1) visibleArchs.delete(a.name);
Expand Down Expand Up @@ -385,9 +391,9 @@ <h1>⛏ The Fossil Record — RustChain Attestation Archaeology</h1>
const d = new Date(ep.ts);
const timeStr = d.toLocaleString();

let html = `<div class="tip-epoch">Epoch #${ep.index + 1} · ${timeStr}</div>`;
let html = `<div class="tip-epoch">Epoch #${ep.index + 1} · ${escapeHtml(timeStr)}</div>`;
if (arch) {
html += `<div class="tip-arch" style="color:${arch.color}">${arch.name}</div>`;
html += `<div class="tip-arch" style="color:${escapeHtml(arch.color)}">${escapeHtml(arch.name)}</div>`;
html += `<div>Attestations: <b>${ep.counts[hoverArch]}</b></div>`;
}

Expand All @@ -397,7 +403,7 @@ <h1>⛏ The Fossil Record — RustChain Attestation Archaeology</h1>
ARCHS.forEach((a, ai) => {
if (!visibleArchs.has(a.name)) return;
const pct = Math.round(ep.counts[ai] / total * 100);
html += `<span style="color:${a.color}">${a.name}</span>: ${ep.counts[ai]} (${pct}%)&nbsp; `;
html += `<span style="color:${escapeHtml(a.color)}">${escapeHtml(a.name)}</span>: ${ep.counts[ai]} (${pct}%)&nbsp; `;
});
html += `</div>`;
html += `<div style="margin-top:4px;color:#666;font-size:0.6rem">Total: ${total}</div>`;
Expand Down
Loading