(function() { var C = window.ExplorerCommon; function badge(text, variant) { return '' + C.esc(text) + ''; } function renderNode(data) { document.title = 'Node ' + C.short(data.address || data.pub_key || '', 16) + ' | DChain Explorer'; // Profile card document.getElementById('nodeNickname').textContent = data.address ? C.short(data.address, 24) : 'Node'; document.getElementById('nodeAddressShort').textContent = data.pub_key ? C.short(data.pub_key, 32) : '—'; document.getElementById('nodeBalanceVal').textContent = data.node_balance || C.toToken(data.node_balance_ut || 0); document.getElementById('nodeReputationRank').textContent = 'Rank: ' + (data.reputation_rank || '—'); // Badges var badges = ''; if (data.blocks_produced > 0) badges += badge('Validator', 'accent'); if (data.relay_proofs > 0) badges += badge('Relay Node', 'relay'); if (!badges) badges = badge('Observer', 'muted'); document.getElementById('nodeBadges').innerHTML = badges; // Address field var addrEl = document.getElementById('nodeAddress'); addrEl.textContent = data.address || '—'; addrEl.href = data.pub_key ? '/address?address=' + encodeURIComponent(data.pub_key) : '#'; document.getElementById('nodeAddressRaw').textContent = data.address || ''; // PubKey field document.getElementById('nodePubKey').textContent = data.pub_key || '—'; // Wallet binding if (data.wallet_binding_address) { var link = document.getElementById('bindingLink'); link.textContent = data.wallet_binding_address; link.href = '/address?address=' + encodeURIComponent(data.wallet_binding_pub_key || data.wallet_binding_address); document.getElementById('bindingBalance').textContent = data.wallet_binding_balance || '—'; document.getElementById('bindingRow').style.display = ''; } else { document.getElementById('bindingRow').style.display = 'none'; } // Stats document.getElementById('repScore').textContent = String(data.reputation_score || 0); document.getElementById('repRank').textContent = data.reputation_rank || '—'; document.getElementById('repBlocks').textContent = String(data.blocks_produced || 0); var rw = data.recent_window_blocks || 0; var rp = data.recent_blocks_produced || 0; document.getElementById('recentProduced').textContent = 'last ' + rw + ' blocks: ' + rp; document.getElementById('repRelay').textContent = String(data.relay_proofs || 0); document.getElementById('repHeartbeats').textContent = String(data.heartbeats || 0); var slash = data.slash_count || 0; document.getElementById('repSlash').textContent = slash > 0 ? slash + ' slashes' : ''; // Rewards document.getElementById('recentRewards').textContent = data.recent_rewards || C.toToken(data.recent_rewards_ut || 0); document.getElementById('windowBlocks').textContent = 'window: last ' + rw + ' blocks'; document.getElementById('lifetimeReward').textContent = data.lifetime_base_reward || C.toToken(0); document.getElementById('nodeBalance').textContent = data.node_balance || C.toToken(data.node_balance_ut || 0); document.getElementById('mainContent').style.display = ''; C.refreshIcons(); } async function loadNode(nodeID) { if (!nodeID) return; C.setStatus('Loading…', 'warn'); document.getElementById('mainContent').style.display = 'none'; try { var data = await C.fetchJSON('/api/node/' + encodeURIComponent(nodeID) + '?window=300'); renderNode(data); window.history.replaceState({}, '', '/node?node=' + encodeURIComponent(nodeID)); C.setStatus('', ''); } catch (e) { C.setStatus('Load failed: ' + e.message, 'err'); } } /* ── Copy buttons ────────────────────────────────────────────────────────── */ document.addEventListener('click', function(e) { var t = e.target; if (!t) return; var btn = t.closest ? t.closest('.copy-btn') : null; if (btn) { var src = document.getElementById(btn.dataset.copyId); if (src) { navigator.clipboard.writeText(src.textContent || '').catch(function() {}); btn.classList.add('copy-btn-done'); setTimeout(function() { btn.classList.remove('copy-btn-done'); }, 1200); } } }); /* ── Wiring ────────────────────────────────────────────────────────────── */ document.getElementById('nodeBtn').addEventListener('click', function() { var val = (document.getElementById('nodeInput').value || '').trim(); if (val) loadNode(val); }); document.getElementById('nodeInput').addEventListener('keydown', function(e) { if (e.key === 'Enter') document.getElementById('nodeBtn').click(); }); var initial = C.q('node') || C.q('pk'); if (initial) { document.getElementById('nodeInput').value = initial; loadNode(initial); } })();