(function() { var C = window.ExplorerCommon; var params = new URLSearchParams(window.location.search); var tokenID = params.get('id'); var nftID = params.get('nft'); function kv(icon, label, valHtml) { return '
' + '
' + label + '
' + '
' + valHtml + '
' + '
'; } function copyBtn(id) { return ''; } function hiddenSpan(id, val) { return ''; } /* ── Fungible token ──────────────────────────────────────────────────────── */ async function loadToken() { C.setStatus('Loading token…', 'warn'); try { var data = await C.fetchJSON('/api/tokens/' + tokenID); if (!data || !data.token_id) { C.setStatus('Token not found.', 'err'); return; } document.title = data.symbol + ' | DChain Explorer'; document.getElementById('bannerType').textContent = 'Fungible Token'; document.getElementById('bannerName').textContent = data.name + ' (' + data.symbol + ')'; document.getElementById('bannerBlock').textContent = 'block ' + (data.issued_at || 0); document.getElementById('bannerIcon').querySelector('i').setAttribute('data-lucide', 'coins'); var d = data.decimals || 0; var supplyFmt = formatSupply(data.total_supply || 0, d); var rows = ''; rows += kv('hash', 'Token ID', '' + C.esc(data.token_id) + '' + copyBtn('tid')); rows += kv('type', 'Symbol', '' + C.esc(data.symbol) + ''); rows += kv('tag', 'Name', C.esc(data.name)); rows += kv('layers-3', 'Decimals', '' + d + ''); rows += kv('bar-chart-2', 'Total Supply', '' + C.esc(supplyFmt) + ''); rows += kv('user', 'Issuer', '' + C.short(data.issuer, 20) + '' + hiddenSpan('issuerRaw', data.issuer) + copyBtn('issuerRaw')); rows += kv('blocks', 'Issued at block', '' + (data.issued_at || 0) + ''); document.getElementById('kvList').innerHTML = rows; document.getElementById('rawJSON').textContent = JSON.stringify(data, null, 2); document.getElementById('tabRaw').style.display = ''; document.getElementById('mainContent').style.display = ''; C.setStatus('', ''); C.refreshIcons(); C.wireClipboard(); } catch(e) { C.setStatus('Load failed: ' + e.message, 'err'); } } /* ── NFT ─────────────────────────────────────────────────────────────────── */ async function loadNFT() { C.setStatus('Loading NFT…', 'warn'); try { var data = await C.fetchJSON('/api/nfts/' + nftID); var n = data && data.nft ? data.nft : data; if (!n || !n.nft_id) { C.setStatus('NFT not found.', 'err'); return; } document.title = n.name + ' | DChain Explorer'; document.getElementById('bannerType').textContent = n.burned ? 'NFT (Burned)' : 'NFT'; document.getElementById('bannerName').textContent = n.name; document.getElementById('bannerBlock').textContent = 'minted block ' + (n.minted_at || 0); document.getElementById('bannerIcon').querySelector('i').setAttribute('data-lucide', 'image'); if (n.burned) document.getElementById('banner').classList.add('tx-banner-err'); // Show image if URI looks like an image if (n.uri && /\.(png|jpg|jpeg|gif|svg|webp)/i.test(n.uri)) { document.getElementById('nftImage').src = n.uri; document.getElementById('nftImageWrap').style.display = ''; } var ownerAddr = data.owner_address || ''; var rows = ''; rows += kv('hash', 'NFT ID', '' + C.esc(n.nft_id) + '' + copyBtn('nid')); rows += kv('tag', 'Name', C.esc(n.name)); if (n.description) rows += kv('file-text', 'Description', C.esc(n.description)); if (n.uri) rows += kv('link', 'Metadata URI', '' + C.esc(n.uri) + ''); if (!n.burned && n.owner) { rows += kv('user', 'Owner', '' + C.short(ownerAddr || n.owner, 20) + '' + hiddenSpan('ownerRaw', n.owner) + copyBtn('ownerRaw')); } else if (n.burned) { rows += kv('flame', 'Status', 'Burned'); } rows += kv('user-check', 'Issuer', '' + C.short(n.issuer, 20) + ''); rows += kv('blocks', 'Minted at block', '' + (n.minted_at || 0) + ''); document.getElementById('kvList').innerHTML = rows; // Attributes if (n.attributes) { try { var attrs = JSON.parse(n.attributes); var keys = Object.keys(attrs); if (keys.length) { var html = ''; keys.forEach(function(k) { html += '
' + C.esc(k) + '
' + '
' + C.esc(String(attrs[k])) + '
'; }); document.getElementById('attrsGrid').innerHTML = html; document.getElementById('attrsSection').style.display = ''; } } catch(_) {} } document.getElementById('rawJSON').textContent = JSON.stringify(data, null, 2); document.getElementById('tabRaw').style.display = ''; document.getElementById('mainContent').style.display = ''; C.setStatus('', ''); C.refreshIcons(); C.wireClipboard(); } catch(e) { C.setStatus('Load failed: ' + e.message, 'err'); } } /* ── Helpers ─────────────────────────────────────────────────────────────── */ function formatSupply(supply, decimals) { if (decimals === 0) return supply.toLocaleString(); var d = Math.pow(10, decimals); var whole = Math.floor(supply / d); var frac = supply % d; if (frac === 0) return whole.toLocaleString(); return whole.toLocaleString() + '.' + String(frac).padStart(decimals, '0').replace(/0+$/, ''); } /* ── Tabs ────────────────────────────────────────────────────────────────── */ document.getElementById('tabOverview').addEventListener('click', function() { document.getElementById('paneOverview').style.display = ''; document.getElementById('paneRaw').style.display = 'none'; document.getElementById('tabOverview').classList.add('tx-tab-active'); document.getElementById('tabRaw').classList.remove('tx-tab-active'); }); document.getElementById('tabRaw').addEventListener('click', function() { document.getElementById('paneOverview').style.display = 'none'; document.getElementById('paneRaw').style.display = ''; document.getElementById('tabRaw').classList.add('tx-tab-active'); document.getElementById('tabOverview').classList.remove('tx-tab-active'); }); /* ── Boot ────────────────────────────────────────────────────────────────── */ if (nftID) loadNFT(); else if (tokenID) loadToken(); else C.setStatus('No token or NFT ID provided.', 'err'); })();