SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "blocks-list.js")
31 STORE("descrHdr", "Block list pagination renderer")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "16f5be99535f1cfd7119f84501310ec02f2b1f1f495a031064e14ac30b5034cc")
37 STORE("fileCheckS", "cdbc6fbc758a7580fef2bfc8eaa63cd0e60cab8eeaa19ba50d40c7b752fd378")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name: 'blocks-list',
version: '1.0.0',
BLOCKS_PER_PAGE: 10,
currentPage: 1,
totalPages: 1,
currentHeight: 0,
isLoading: false,
async renderBlocksExplorer(x) {
try {
const i = await x('DERO.GetInfo');
this.currentHeight = i ? i.height || i.topoheight || 0 : 0;
this.currentPage = 1;
const buffer = 2;
const ah = this.currentHeight - buffer;
this.totalPages = Math.ceil(ah / this.BLOCKS_PER_PAGE);
let result = '<div class="enhanced-card">';
result += '<div class="card-header">';
result += '<div><h2 style="color:#fff;margin:0;font-size:1.6rem;">DERO Block Explorer</h2>';
result += '<div style="color:#b3b3b3;font-size:0.9rem;">Real-time blockchain explorer • Total blocks: ' + this.currentHeight.toLocaleString() + '</div></div>';
result += '<div class="actions"><button onclick="loadBlocks(window.xswd?.call?.bind(window.xswd)||window.gx)" style="background:rgba(82,200,219,0.1);border:1px solid #52c8db;color:#52c8db;padding:0.5rem 1rem;border-radius:6px;cursor:pointer;">Refresh</button></div>';
result += '</div>';
result += '<div class="card-content">';
result += this.renderPagination();
result += '<div id="blocks-container"><div style="text-align:center;color:#888;padding:2rem;background:rgba(0,0,0,0.2);border-radius:8px;"><div style="font-size:1.1rem;margin-bottom:0.5rem;">Loading blockchain data...</div></div></div>';
result += this.renderPagination();
result += '</div></div>';
return result;
} catch (e) {
return '<div class="enhanced-card"><div class="card-header"><h2>DERO Block Explorer</h2></div><div class="card-content"><div style="color:#ef4444;">Connection Error: Unable to connect to DERO daemon</div></div></div>';
}
},
renderBlocksList(b) {
if (!b || b.length === 0) {
return '<div style="text-align:center;color:#888;padding:2rem;"><div>No blocks found</div><div>Try refreshing or adjusting your search criteria</div></div>';
}
const rw = b.map(bk => {
const h = bk.header;
if (!h) return '';
// Use EXACT same logic as main-utils.js cr() function for consistency
const now = Date.now() / 1000;
let bt = h.timestamp || 0;
if (bt > 1e12) bt /= 1000; // Convert milliseconds to seconds if needed
const age = Math.abs(now - bt);
// Format age exactly like cr() function
let ad = '';
if (age < 60) ad = Math.floor(age) + 's';
else if (age < 3600) ad = Math.floor(age / 60) + 'm';
else if (age < 86400) ad = Math.floor(age / 3600) + 'h';
else if (age < 86400 * 7) ad = Math.floor(age / 86400) + 'd';
else ad = '7d+';
// Extract all data exactly like cr() function
const bs = h.block_size || 0;
let sd = '';
if (bs < 1024) sd = bs + 'B';
else if (bs < 1024 * 1024) sd = Math.round(bs / 1024) + 'KB';
else sd = Math.round(bs / (1024 * 1024)) + 'MB';
const m = h.miners?.length || bk.blockData?.miners?.length || 1;
const d = (h.difficulty || 0).toLocaleString();
const fh = h.hash || 'N/A';
return '<div style="display:grid;grid-template-columns:180px 1fr 70px 80px 100px 70px;gap:0.8rem;padding:0.75rem;border-bottom:1px solid rgba(255,255,255,0.05);align-items:center;font-size:0.85rem;transition:background 0.2s ease;cursor:pointer;" onclick="window.location.hash=\'block/' + bk.height + '\'" onmouseover="this.style.background=\'rgba(255,255,255,0.02)\'" onmouseout="this.style.background=\'transparent\'">' +
'<div><div style="color:#52c8db;font-weight:600;font-size:1rem;">' + bk.height.toLocaleString() + '</div><div style="color:#888;font-size:0.75rem;margin-top:0.2rem;">Block Height</div></div>' +
'<div style="font-family:monospace;color:#b959b6;font-size:0.75rem;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + fh + '</div>' +
'<div style="color:#888;text-align:center;">' + ad + '</div>' +
'<div style="color:#fbbf24;text-align:center;font-weight:500;">' + sd + '</div>' +
'<div style="color:#4ade80;text-align:center;font-size:0.8rem;">' + d + '</div>' +
'<div style="color:#888;text-align:right;font-size:0.8rem;">' + m + '</div>' +
'</div>';
}).join('');
return '<div style="background:rgba(0,0,0,0.2);border:1px solid rgba(82,200,219,0.3);border-radius:8px;overflow:hidden;"><div style="display:grid;grid-template-columns:180px 1fr 70px 80px 100px 70px;gap:0.8rem;padding:1rem;border-bottom:2px solid rgba(82,200,219,0.3);font-weight:600;font-size:0.9rem;color:#52c8db;background:rgba(82,200,219,0.1);"><div>Block Height</div><div>Hash</div><div style="text-align:center;">Age</div><div style="text-align:center;">Size</div><div style="text-align:center;">Difficulty</div><div style="text-align:right;">Miners</div></div>' + rw + '</div>';
},
renderPagination() {
const f = this.currentPage === 1;
const l = this.currentPage === this.totalPages;
// Following TELA Design System standards for pagination
const btnStyle = 'background:rgba(82,200,219,0.1);border:1px solid #52c8db;color:#52c8db;padding:0.75rem 1.5rem;border-radius:6px;cursor:pointer;transition:all 0.2s ease;font-weight:500;font-size:0.9rem;';
const btnDisabledStyle = 'background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);color:#666;padding:0.75rem 1.5rem;border-radius:6px;cursor:not-allowed;font-weight:500;font-size:0.9rem;opacity:0.5;';
const currentStyle = 'background:rgba(82,200,219,0.15);border:1px solid #52c8db;color:#52c8db;padding:0.75rem 1.5rem;border-radius:6px;font-weight:600;font-size:0.9rem;';
let ph = '<div class="pagination" style="display:flex;justify-content:center;align-items:center;gap:0.75rem;padding:1.5rem;background:rgba(0,0,0,0.2);border:1px solid rgba(82,200,219,0.3);border-radius:8px;margin:1.5rem 0;">';
ph += '<button class="pagination-btn" style="' + (f ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(1)" ' + (f ? 'disabled' : '') + '>«« First</button>';
ph += '<button class="pagination-btn" style="' + (f ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + (this.currentPage - 1) + ')" ' + (f ? 'disabled' : '') + '>« Previous</button>';
ph += '<div style="' + currentStyle + '">Page ' + this.currentPage + ' of ' + this.totalPages + '</div>';
ph += '<button class="pagination-btn" style="' + (l ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + (this.currentPage + 1) + ')" ' + (l ? 'disabled' : '') + '>Next »</button>';
ph += '<button class="pagination-btn" style="' + (l ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + this.totalPages + ')" ' + (l ? 'disabled' : '') + '>Last »»</button>';
ph += '</div>';
// Add pagination button management function
if (!window.disablePaginationButtons) {
window.disablePaginationButtons = function(disabled) {
const btns = document.querySelectorAll('.pagination-btn');
btns.forEach(btn => {
if (disabled) {
btn.disabled = true;
btn.style.opacity = '0.5';
btn.style.cursor = 'not-allowed';
btn.style.background = 'rgba(255,255,255,0.05)';
btn.style.color = '#666';
const originalText = btn.textContent;
btn.setAttribute('data-original-text', originalText);
btn.innerHTML = 'Loading...';
} else {
const originalText = btn.getAttribute('data-original-text');
if (originalText) {
btn.textContent = originalText;
btn.removeAttribute('data-original-text');
}
btn.disabled = false;
btn.style.opacity = '1';
btn.style.cursor = 'pointer';
btn.style.background = 'rgba(82,200,219,0.1)';
btn.style.color = '#52c8db';
}
});
};
}
return ph;
},
async loadBlocksPage(page, xswdCall) {
if (!xswdCall) return;
this.currentPage = Math.max(1, Math.min(page, this.totalPages));
const container = document.getElementById('blocks-container');
if (!container) return;
container.innerHTML = '<div style="text-align:center;padding:2rem;"><div style="color:#52c8db;">Loading Page ' + this.currentPage + '...</div></div>';
try {
const buffer = 2;
const adjustedHeight = this.currentHeight - buffer;
const startHeight = adjustedHeight - (this.currentPage - 1) * this.BLOCKS_PER_PAGE;
const endHeight = Math.max(1, startHeight - this.BLOCKS_PER_PAGE + 1);
const blocks = [];
for (let h = startHeight; h >= endHeight; h--) {
try {
if (!window.xswd || !window.xswd.isConnected) break;
const blockData = await xswdCall('DERO.GetBlock', {height: h});
if (blockData && blockData.block_header) {
blocks.push({height: h, header: blockData.block_header, blockData: blockData});
}
await new Promise(resolve => setTimeout(resolve, 50));
} catch (e) {
if (e.message.includes('not connected') || e.message.includes('Timeout')) break;
}
}
container.innerHTML = this.renderBlocksList(blocks);
const paginationElements = document.querySelectorAll('.pagination');
paginationElements.forEach(pag => {
pag.outerHTML = this.renderPagination();
});
} catch (error) {
container.innerHTML = '<div style="color:#ef4444;text-align:center;padding:2rem;">Failed to load blocks: ' + error.message + '</div>';
}
}
})
*/ |
SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "blocks-list.js")
31 STORE("descrHdr", "Block list pagination renderer")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "16f5be99535f1cfd7119f84501310ec02f2b1f1f495a031064e14ac30b5034cc")
37 STORE("fileCheckS", "cdbc6fbc758a7580fef2bfc8eaa63cd0e60cab8eeaa19ba50d40c7b752fd378")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name: 'blocks-list',
version: '1.0.0',
BLOCKS_PER_PAGE: 10,
currentPage: 1,
totalPages: 1,
currentHeight: 0,
isLoading: false,
async renderBlocksExplorer(x) {
try {
const i = await x('DERO.GetInfo');
this.currentHeight = i ? i.height || i.topoheight || 0 : 0;
this.currentPage = 1;
const buffer = 2;
const ah = this.currentHeight - buffer;
this.totalPages = Math.ceil(ah / this.BLOCKS_PER_PAGE);
let result = '<div class="enhanced-card">';
result += '<div class="card-header">';
result += '<div><h2 style="color:#fff;margin:0;font-size:1.6rem;">DERO Block Explorer</h2>';
result += '<div style="color:#b3b3b3;font-size:0.9rem;">Real-time blockchain explorer • Total blocks: ' + this.currentHeight.toLocaleString() + '</div></div>';
result += '<div class="actions"><button onclick="loadBlocks(window.xswd?.call?.bind(window.xswd)||window.gx)" style="background:rgba(82,200,219,0.1);border:1px solid #52c8db;color:#52c8db;padding:0.5rem 1rem;border-radius:6px;cursor:pointer;">Refresh</button></div>';
result += '</div>';
result += '<div class="card-content">';
result += this.renderPagination();
result += '<div id="blocks-container"><div style="text-align:center;color:#888;padding:2rem;background:rgba(0,0,0,0.2);border-radius:8px;"><div style="font-size:1.1rem;margin-bottom:0.5rem;">Loading blockchain data...</div></div></div>';
result += this.renderPagination();
result += '</div></div>';
return result;
} catch (e) {
return '<div class="enhanced-card"><div class="card-header"><h2>DERO Block Explorer</h2></div><div class="card-content"><div style="color:#ef4444;">Connection Error: Unable to connect to DERO daemon</div></div></div>';
}
},
renderBlocksList(b) {
if (!b || b.length === 0) {
return '<div style="text-align:center;color:#888;padding:2rem;"><div>No blocks found</div><div>Try refreshing or adjusting your search criteria</div></div>';
}
const rw = b.map(bk => {
const h = bk.header;
if (!h) return '';
// Use EXACT same logic as main-utils.js cr() function for consistency
const now = Date.now() / 1000;
let bt = h.timestamp || 0;
if (bt > 1e12) bt /= 1000; // Convert milliseconds to seconds if needed
const age = Math.abs(now - bt);
// Format age exactly like cr() function
let ad = '';
if (age < 60) ad = Math.floor(age) + 's';
else if (age < 3600) ad = Math.floor(age / 60) + 'm';
else if (age < 86400) ad = Math.floor(age / 3600) + 'h';
else if (age < 86400 * 7) ad = Math.floor(age / 86400) + 'd';
else ad = '7d+';
// Extract all data exactly like cr() function
const bs = h.block_size || 0;
let sd = '';
if (bs < 1024) sd = bs + 'B';
else if (bs < 1024 * 1024) sd = Math.round(bs / 1024) + 'KB';
else sd = Math.round(bs / (1024 * 1024)) + 'MB';
const m = h.miners?.length || bk.blockData?.miners?.length || 1;
const d = (h.difficulty || 0).toLocaleString();
const fh = h.hash || 'N/A';
return '<div style="display:grid;grid-template-columns:180px 1fr 70px 80px 100px 70px;gap:0.8rem;padding:0.75rem;border-bottom:1px solid rgba(255,255,255,0.05);align-items:center;font-size:0.85rem;transition:background 0.2s ease;cursor:pointer;" onclick="window.location.hash=\'block/' + bk.height + '\'" onmouseover="this.style.background=\'rgba(255,255,255,0.02)\'" onmouseout="this.style.background=\'transparent\'">' +
'<div><div style="color:#52c8db;font-weight:600;font-size:1rem;">' + bk.height.toLocaleString() + '</div><div style="color:#888;font-size:0.75rem;margin-top:0.2rem;">Block Height</div></div>' +
'<div style="font-family:monospace;color:#b959b6;font-size:0.75rem;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + fh + '</div>' +
'<div style="color:#888;text-align:center;">' + ad + '</div>' +
'<div style="color:#fbbf24;text-align:center;font-weight:500;">' + sd + '</div>' +
'<div style="color:#4ade80;text-align:center;font-size:0.8rem;">' + d + '</div>' +
'<div style="color:#888;text-align:right;font-size:0.8rem;">' + m + '</div>' +
'</div>';
}).join('');
return '<div style="background:rgba(0,0,0,0.2);border:1px solid rgba(82,200,219,0.3);border-radius:8px;overflow:hidden;"><div style="display:grid;grid-template-columns:180px 1fr 70px 80px 100px 70px;gap:0.8rem;padding:1rem;border-bottom:2px solid rgba(82,200,219,0.3);font-weight:600;font-size:0.9rem;color:#52c8db;background:rgba(82,200,219,0.1);"><div>Block Height</div><div>Hash</div><div style="text-align:center;">Age</div><div style="text-align:center;">Size</div><div style="text-align:center;">Difficulty</div><div style="text-align:right;">Miners</div></div>' + rw + '</div>';
},
renderPagination() {
const f = this.currentPage === 1;
const l = this.currentPage === this.totalPages;
// Following TELA Design System standards for pagination
const btnStyle = 'background:rgba(82,200,219,0.1);border:1px solid #52c8db;color:#52c8db;padding:0.75rem 1.5rem;border-radius:6px;cursor:pointer;transition:all 0.2s ease;font-weight:500;font-size:0.9rem;';
const btnDisabledStyle = 'background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);color:#666;padding:0.75rem 1.5rem;border-radius:6px;cursor:not-allowed;font-weight:500;font-size:0.9rem;opacity:0.5;';
const currentStyle = 'background:rgba(82,200,219,0.15);border:1px solid #52c8db;color:#52c8db;padding:0.75rem 1.5rem;border-radius:6px;font-weight:600;font-size:0.9rem;';
let ph = '<div class="pagination" style="display:flex;justify-content:center;align-items:center;gap:0.75rem;padding:1.5rem;background:rgba(0,0,0,0.2);border:1px solid rgba(82,200,219,0.3);border-radius:8px;margin:1.5rem 0;">';
ph += '<button class="pagination-btn" style="' + (f ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(1)" ' + (f ? 'disabled' : '') + '>«« First</button>';
ph += '<button class="pagination-btn" style="' + (f ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + (this.currentPage - 1) + ')" ' + (f ? 'disabled' : '') + '>« Previous</button>';
ph += '<div style="' + currentStyle + '">Page ' + this.currentPage + ' of ' + this.totalPages + '</div>';
ph += '<button class="pagination-btn" style="' + (l ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + (this.currentPage + 1) + ')" ' + (l ? 'disabled' : '') + '>Next »</button>';
ph += '<button class="pagination-btn" style="' + (l ? btnDisabledStyle : btnStyle) + '" onclick="window.loadBlocksPage(' + this.totalPages + ')" ' + (l ? 'disabled' : '') + '>Last »»</button>';
ph += '</div>';
// Add pagination button management function
if (!window.disablePaginationButtons) {
window.disablePaginationButtons = function(disabled) {
const btns = document.querySelectorAll('.pagination-btn');
btns.forEach(btn => {
if (disabled) {
btn.disabled = true;
btn.style.opacity = '0.5';
btn.style.cursor = 'not-allowed';
btn.style.background = 'rgba(255,255,255,0.05)';
btn.style.color = '#666';
const originalText = btn.textContent;
btn.setAttribute('data-original-text', originalText);
btn.innerHTML = 'Loading...';
} else {
const originalText = btn.getAttribute('data-original-text');
if (originalText) {
btn.textContent = originalText;
btn.removeAttribute('data-original-text');
}
btn.disabled = false;
btn.style.opacity = '1';
btn.style.cursor = 'pointer';
btn.style.background = 'rgba(82,200,219,0.1)';
btn.style.color = '#52c8db';
}
});
};
}
return ph;
},
async loadBlocksPage(page, xswdCall) {
if (!xswdCall) return;
this.currentPage = Math.max(1, Math.min(page, this.totalPages));
const container = document.getElementById('blocks-container');
if (!container) return;
container.innerHTML = '<div style="text-align:center;padding:2rem;"><div style="color:#52c8db;">Loading Page ' + this.currentPage + '...</div></div>';
try {
const buffer = 2;
const adjustedHeight = this.currentHeight - buffer;
const startHeight = adjustedHeight - (this.currentPage - 1) * this.BLOCKS_PER_PAGE;
const endHeight = Math.max(1, startHeight - this.BLOCKS_PER_PAGE + 1);
const blocks = [];
for (let h = startHeight; h >= endHeight; h--) {
try {
if (!window.xswd || !window.xswd.isConnected) break;
const blockData = await xswdCall('DERO.GetBlock', {height: h});
if (blockData && blockData.block_header) {
blocks.push({height: h, header: blockData.block_header, blockData: blockData});
}
await new Promise(resolve => setTimeout(resolve, 50));
} catch (e) {
if (e.message.includes('not connected') || e.message.includes('Timeout')) break;
}
}
container.innerHTML = this.renderBlocksList(blocks);
const paginationElements = document.querySelectorAll('.pagination');
paginationElements.forEach(pag => {
pag.outerHTML = this.renderPagination();
});
} catch (error) {
container.innerHTML = '<div style="color:#ef4444;text-align:center;padding:2rem;">Failed to load blocks: ' + error.message + '</div>';
}
}
})
*/'] |