(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 '' + C.esc(val) + ' ';
}
/* ── 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');
})();