From 7ce3b5477e76f15b135ac402119cf9d0c6a12ab3 Mon Sep 17 00:00:00 2001 From: Joe Uhren Date: Fri, 3 Nov 2023 18:42:34 -0600 Subject: [PATCH] Optimized global client-side javascript code -Javascript in the layout.pug has been moved around in an attempt to only load code into the client based on certain settings such as the type of menu (side or top) in order to slim down the loading of pages by not including unnecessary code -Fixed a bug on the richlist page where the last updated date and logo spinning animation would fail to load if the distribution chart was disabled in the settings -The .ext/getsummary api has been modified to only return the connection and block counts when necessary -The getmasternodecount rpc api will no longer fetch data unless it is enabled in settings --- app.js | 136 ++--- lib/explorer.js | 44 +- views/layout.pug | 1410 ++++++++++++++++++++++---------------------- views/richlist.pug | 33 +- 4 files changed, 832 insertions(+), 791 deletions(-) diff --git a/app.js b/app.js index 3f0ac9c..5fc32b8 100644 --- a/app.js +++ b/app.js @@ -440,82 +440,86 @@ app.use('/ext/getaddresstxs/:address/:start/:length', function(req, res) { res.end('This method is disabled'); }); -app.use('/ext/getsummary', function(req, res) { - // check if the getsummary api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer) - if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getsummary.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) { +function get_connection_and_block_counts(get_data, cb) { + // check if the connection and block counts should be returned + if (get_data) { lib.get_connectioncount(function(connections) { lib.get_blockcount(function(blockcount) { - // check if this is a footer-only method that should only return the connection count and block count - if (req.headers['footer-only'] != null && req.headers['footer-only'] == 'true') { - // only return the connection count and block count - res.send({ - connections: (connections ? connections : '-'), - blockcount: (blockcount ? blockcount : '-') - }); - } else { - lib.get_hashrate(function(hashrate) { - db.get_stats(settings.coin.name, function (stats) { - lib.get_masternodecount(function(masternodestotal) { - lib.get_difficulty(function(difficulty) { - difficultyHybrid = ''; + return cb(connections, blockcount); + }); + }); + } else + return cb(null, null); +} - if (difficulty && difficulty['proof-of-work']) { - if (settings.shared_pages.difficulty == 'Hybrid') { - difficultyHybrid = 'POS: ' + difficulty['proof-of-stake']; - difficulty = 'POW: ' + difficulty['proof-of-work']; - } else if (settings.shared_pages.difficulty == 'POW') - difficulty = difficulty['proof-of-work']; - else - difficulty = difficulty['proof-of-stake']; +app.use('/ext/getsummary', function(req, res) { + const isInternal = (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1); + + // check if the getsummary api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer) + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getsummary.enabled == true) || isInternal) { + // check if this is a footer-only method that should only return the connection count and block count + if (req.headers['footer-only'] != null && req.headers['footer-only'] == 'true') { + // only return the connection count and block count + get_connection_and_block_counts(true, function(connections, blockcount) { + res.send({ + connections: (connections ? connections : '-'), + blockcount: (blockcount ? blockcount : '-') + }); + }); + } else { + // get the connection and block counts only if this is NOT an internal call + get_connection_and_block_counts(!isInternal, function(connections, blockcount) { + lib.get_hashrate(function(hashrate) { + db.get_stats(settings.coin.name, function (stats) { + lib.get_masternodecount(function(masternodestotal) { + lib.get_difficulty(function(difficulty) { + let difficultyHybrid = ''; + + if (difficulty && difficulty['proof-of-work']) { + if (settings.shared_pages.difficulty == 'Hybrid') { + difficultyHybrid = 'POS: ' + difficulty['proof-of-stake']; + difficulty = 'POW: ' + difficulty['proof-of-work']; + } else if (settings.shared_pages.difficulty == 'POW') + difficulty = difficulty['proof-of-work']; + else + difficulty = difficulty['proof-of-stake']; + } + + if (hashrate == 'There was an error. Check your console.') + hashrate = 0; + + let mn_total = 0; + let mn_enabled = 0; + + // check if the masternode count api is enabled + if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { + // masternode count api is available + if (masternodestotal) { + if (masternodestotal.total) + mn_total = masternodestotal.total; + + if (masternodestotal.enabled) + mn_enabled = masternodestotal.enabled; } + } - if (hashrate == 'There was an error. Check your console.') - hashrate = 0; - - // check if the masternode count api is enabled - if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { - // masternode count api is available - var mn_total = 0; - var mn_enabled = 0; - - if (masternodestotal) { - if (masternodestotal.total) - mn_total = masternodestotal.total; - - if (masternodestotal.enabled) - mn_enabled = masternodestotal.enabled; - } - - res.send({ - difficulty: (difficulty ? difficulty : '-'), - difficultyHybrid: difficultyHybrid, - supply: (stats == null || stats.supply == null ? 0 : stats.supply), - hashrate: hashrate, - lastPrice: (stats == null || stats.last_price == null ? 0 : stats.last_price), - connections: (connections ? connections : '-'), - masternodeCountOnline: (masternodestotal ? mn_enabled : '-'), - masternodeCountOffline: (masternodestotal ? Math.floor(mn_total - mn_enabled) : '-'), - blockcount: (blockcount ? blockcount : '-') - }); - } else { - // masternode count api is not available - res.send({ - difficulty: (difficulty ? difficulty : '-'), - difficultyHybrid: difficultyHybrid, - supply: (stats == null || stats.supply == null ? 0 : stats.supply), - hashrate: hashrate, - lastPrice: (stats == null || stats.last_price == null ? 0 : stats.last_price), - connections: (connections ? connections : '-'), - blockcount: (blockcount ? blockcount : '-') - }); - } + res.send({ + difficulty: (difficulty ? difficulty : '-'), + difficultyHybrid: difficultyHybrid, + supply: (stats == null || stats.supply == null ? 0 : stats.supply), + hashrate: hashrate, + lastPrice: (stats == null || stats.last_price == null ? 0 : stats.last_price), + connections: (connections ? connections : '-'), + blockcount: (blockcount ? blockcount : '-'), + masternodeCountOnline: (masternodestotal && mn_enabled != 0 ? mn_enabled : '-'), + masternodeCountOffline: (masternodestotal && mn_total != 0 ? Math.floor(mn_total - mn_enabled) : '-') }); }); }); }); - } + }); }); - }); + } } else res.end('This method is disabled'); }); diff --git a/lib/explorer.js b/lib/explorer.js index fc50d76..ea597c2 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -347,27 +347,33 @@ module.exports = { }, get_masternodecount: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.getmasternodecount); + // check if the masternode count api is enabled + if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { + var cmd = prepareRpcCommand(settings.api_cmds.getmasternodecount); - if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.api_cmds.use_rpc) { - rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { - // check if an error msg was received from the rpc server - if (response == 'There was an error. Check your console.') - return cb(null); - else - return cb(response); - }); + if (!(cmd.method == '' && cmd.parameters.length == 0)) { + if (settings.api_cmds.use_rpc) { + rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { + // check if an error msg was received from the rpc server + if (response == 'There was an error. Check your console.') + return cb(null); + else + return cb(response); + }); + } else { + var uri = base_url + 'getmasternodecount'; + + request({uri: uri, json: true}, function (error, response, body) { + // check if an error msg was received from the web api server + if (body == 'There was an error. Check your console.') + return cb(null); + else + return cb(body); + }); + } } else { - var uri = base_url + 'getmasternodecount'; - - request({uri: uri, json: true}, function (error, response, body) { - // check if an error msg was received from the web api server - if (body == 'There was an error. Check your console.') - return cb(null); - else - return cb(body); - }); + // cmd not in use. return null. + return cb(null); } } else { // cmd not in use. return null. diff --git a/views/layout.pug b/views/layout.pug index f7d18c9..febff57 100644 --- a/views/layout.pug +++ b/views/layout.pug @@ -142,101 +142,77 @@ html(lang='en') else - sideBarClasses.push('bg-primary'); - sideBarClasses.push('navbar-dark'); + - var showNetworkPanel = false + if settings.panel1 == 'network_panel' || settings.panel2 == 'network_panel' || settings.panel3 == 'network_panel' || settings.panel4 == 'network_panel' || settings.panel5 == 'network_panel' + - showNetworkPanel = true script. - var sideMarketVisible = false; - var topMenuExpanded = false; - var sideBarClasses = '!{sideBarClasses}'.replace(/,/g, " "); const { OverlayScrollbars } = OverlayScrollbarsGlobal; - /* Special thanks to the stackoverflow community for the getParameterByName function: https://stackoverflow.com/a/901144/3038650 */ + + /* special thanks to the stackoverflow community for the getParameterByName function: https://stackoverflow.com/a/901144/3038650 */ function getParameterByName(name, url = window.location.href) { name = name.replace(/[\[\]]/g, '\\$&'); - var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), + const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, ' ')); } function fixFooterHeightAndPosition() { - var screenWidth = $(window).outerWidth(); + const screenWidth = $(window).outerWidth(); + let socialLinkHeight = 70; if (screenWidth <= 575) { - // Mobile + // mobile $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_mobile}'); + socialLinkHeight = !{settings.shared_pages.page_footer.social_link_percent_height_mobile}; } else if (screenWidth >= 576 && screenWidth <= 991) { - // Tablet + // tablet $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_tablet}'); + socialLinkHeight = !{settings.shared_pages.page_footer.social_link_percent_height_tablet}; } else { - // Desktop + // desktop $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_desktop}'); + socialLinkHeight = !{settings.shared_pages.page_footer.social_link_percent_height_desktop}; } if (!#{settings.shared_pages.page_footer.sticky_footer}) { - // Wait a tick before fixing footer position to give time for elements to be rendered + // wait a tick before fixing footer position to give time for elements to be rendered setTimeout(function() { - // Ensure footer is shown at the bottom of the viewport - var offset = (window.innerHeight - $('#footer-container').position().top - $('#footer-container').outerHeight()); + // ensure footer is shown at the bottom of the viewport + const offset = (window.innerHeight - $('#footer-container').position().top - $('#footer-container').outerHeight()); $('#footer-container').css('margin-top', (offset > 0 ? offset - 1 : '10') + 'px'); if ('#{settings.shared_pages.page_header.menu}' == 'side') fixSidebarHeight(); }, 1); } else { - // Add spacing to the bottom of the body for the sticky footer + // add spacing to the bottom of the body for the sticky footer $('body').css('margin-bottom', ($('#footer-container').outerHeight() + 10) + 'px'); if ('#{settings.shared_pages.page_header.menu}' == 'side') fixSidebarHeight(); } - fixSocialLinkFontSize(); - } - function fixSocialLinkFontSize() { - var fontSize = $('#footer-container').height() * (getSocialLinkHeight() / 100); + // fix social link font size + const fontSize = $('#footer-container').height() * (socialLinkHeight / 100); $('#footer-container .social-link').css('font-size', fontSize); $('#footer-container .social-link > img').css('width', fontSize + 'px').css('height', fontSize + 'px'); } - function fixSidebarHeight() { - if ('#{settings.shared_pages.page_footer.sticky_footer}' != 'true') - $('div#side-nav-bar').css('margin-bottom', -($('div#body-container > div#side-nav-bar').length ? ($('div#footer-container').offset().top - $('div#footer-container').position().top + 1) : 0).toString() + 'px'); - else if ($('div#footer-container').offset().top > ($('#main-container').position().top + $('#main-container').outerHeight(true))) - $('div#side-nav-bar').css('margin-bottom', -($('div#body-container > div#side-nav-bar').length ? ($('div#footer-container').offset().top - ($('#main-container').position().top + $('#main-container').outerHeight(true)) + $('div#footer-container').outerHeight(true)) : 0).toString() + 'px'); - else - $('div#side-nav-bar').css('margin-bottom', ''); - } - function getSocialLinkHeight() { - var retVal = 70; - var screenWidth = $(window).outerWidth(); - - if (screenWidth <= 575) { - // Mobile - retVal = !{settings.shared_pages.page_footer.social_link_percent_height_mobile}; - } else if (screenWidth >= 576 && screenWidth <= 991) { - // Tablet - retVal = !{settings.shared_pages.page_footer.social_link_percent_height_tablet}; - } else { - // Desktop - retVal = !{settings.shared_pages.page_footer.social_link_percent_height_desktop}; - } - - return retVal; - } function enableTooltips() { if ($().tooltip) { - // Enable tooltips only if browser supports them + // enable tooltips only if browser supports them $('[data-bs-toggle="tooltip"]').tooltip(); } } function fixDataTableColumns() { - // Wait 2 ticks before adjusting table columns to give time for elements to be rendered (1 tick doesn't seem to be enough for some tables) - var ColumnAdjustSetIntervalID = setInterval(function() { - // Stop setInterval from running again - clearInterval(ColumnAdjustSetIntervalID); - // Ensure columns are properly aligned + // wait 2 ticks before adjusting table columns to give time for elements to be rendered (1 tick doesn't seem to be enough for some tables) + setTimeout(function() { + // ensure columns are properly aligned $($.fn.dataTable.tables(true)).DataTable().columns.adjust(); - }, 2, 'adjustTableColumns'); + }, 2); } function rotateElement(elementSelector) { - var element = $(elementSelector); + const element = $(elementSelector); if (element.length > 0) { $({ deg: 0 }).animate({ deg: 360 }, { @@ -259,51 +235,54 @@ html(lang='en') rotateElement(elementSelector); }, 100); } - function getNetHashUnits() { - var networkSuffix=''; - switch ('#{settings.shared_pages.page_header.panels.network_panel.nethash_units}') { - case "K": - networkSuffix='(KH/s)'; - break; - case "M": - networkSuffix='(MH/s)'; - break; - case "G": - networkSuffix='(GH/s)'; - break; - case "T": - networkSuffix='(TH/s)'; - break; - case "P": - networkSuffix='(PH/s)'; - break; - case "H": - networkSuffix='(H/s)'; - break; - } - return networkSuffix; - } - function fixTopMenuCollapse(isResizing) { - if (topMenuExpanded && isResizing) { - // force collapse the menu if it is open and the screen is being resized, - // otherwise it could cause problems with the market dropdown after resizing back and forth between mobile and desktop sizes - bootstrap.Collapse.getOrCreateInstance($('#navbar-collapse')).hide(); - topMenuExpanded = false; - } + function update_block_and_connection_stats() { + const summary_headers = { + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'footer-only': 'true' + }; + $.ajax({url: '/ext/getsummary', headers: summary_headers, success: function(json) { + $("#lblConnections").text(json.connections + ' connections'); + $("#lblBlockcount").text(json.blockcount + ' blocks'); + }}); + } + $(document).on('click', 'button.btn-close', function (e) { + e.preventDefault(); + + $('.alert-dismissible').on('closed.bs.alert', function (e) { + e.preventDefault(); + fixFooterHeightAndPosition(); + }); + }); + $(document).on('click', 'button#search-header-button', function (e) { if ($().tooltip) - $('#navbar-toggler-span').tooltip('hide'); - - if (topMenuExpanded) { - $('#search-header-button').hide(); - $('#search-navbar-collapse').addClass('d-none'); - $('#navbar-collapse').css('max-height', ($(window).outerHeight() - ($('#main-header div.navbar-header').outerHeight()) - (#{settings.shared_pages.page_footer.sticky_footer} == true ? $('div#footer-container').outerHeight(true) : 0) - 20).toString() + 'px'); - } else - $('#navbar-collapse').css('max-height', 'none'); - } + $('#search-header-span').tooltip('hide'); + }); + $(window).resize(function () { + fixDataTableColumns(); + fixFooterHeightAndPosition(); + }); $(document).ready(function() { if ('#{active}' != '') $('##{active} > a.nav-link').addClass('active'); + + $('#search-navbar-collapse').on('shown.bs.collapse', function (e) { + fixFooterHeightAndPosition(); + }); + $('#search-navbar-collapse').on('hidden.bs.collapse', function (e) { + fixFooterHeightAndPosition(); + }); + + setInterval(function() { + update_block_and_connection_stats(); + }, 60000); + + update_block_and_connection_stats(); + fixFooterHeightAndPosition(); + enableTooltips(); + }); + if showPanels == true + script. function showTopPanelData(dataElement, loadingElement) { if ($('#' + loadingElement).length) { $('#' + loadingElement).fadeOut('slow', function() { @@ -312,355 +291,11 @@ html(lang='en') }); } } - function update_stats() { - var summary_headers = { - Accept: 'application/json, text/javascript, */*; q=0.01' - }; - - if (#{showPanels} == false) - summary_headers['footer-only'] = 'true'; - - $.ajax({url: '/ext/getsummary', headers: summary_headers, success: function(json) { - if (#{showPanels} == true) { - if (json.masternodeCountOnline == null) - json.masternodeCountOnline = '-'; - if (json.masternodeCountOffline == null) - json.masternodeCountOffline = '-'; - - var mnOnlineText = json.masternodeCountOnline+" node"+(json.masternodeCountOnline == 1 ? "" : "s")+" online"; - var mnOfflineText = json.masternodeCountOffline+" unreachable node"+(json.masternodeCountOffline == 1 ? "" : "s"); - - $("#masternodeCountOnline").text(json.masternodeCountOnline).prop("alt", mnOnlineText).prop("title", mnOnlineText).attr("data-bs-original-title", mnOnlineText); - $("#masternodeCountOffline").text(json.masternodeCountOffline).prop("alt", mnOfflineText).prop("title", mnOfflineText).attr("data-bs-original-title", mnOfflineText); - $("#spnMasternodeCountOnline").prop("alt", mnOnlineText).prop("title", mnOnlineText).attr("data-bs-original-title", mnOnlineText); - $("#spnMasternodeCountOffline").prop("alt", mnOfflineText).prop("title", mnOfflineText).attr("data-bs-original-title", mnOfflineText); - showTopPanelData('masternodepanel', 'masternodePanelLoading'); - - var supplyString = json.supply; - var diffString = json.difficulty; - var hashrateString = json.hashrate; - var splitValue, splitParts; - - if (!isNaN(json.difficulty)) - diffString = Number(json.difficulty).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - if (!isNaN(json.supply)) - supplyString = parseInt(parseFloat(json.supply).toFixed(0)).toLocaleString('en'); - if (!isNaN(json.hashrate)) - hashrateString = Number(json.hashrate).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - $("#supply").text(supplyString); - splitValue = Number(parseFloat(json.lastPrice).toFixed(8) * parseInt(parseFloat(json.supply).toFixed(0))).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - splitParts = splitValue.split('.'); - showTopPanelData('supplypanel', 'supplyPanelLoading'); - - $("#marketCap").html(splitParts[0] + '.' + splitParts[1] + ''); - showTopPanelData('marketCapPanel', 'marketCapPanelLoading'); - - splitParts = diffString.split('.'); - $("#difficulty").html(splitParts[0] + '.' + splitParts[1] + ''); - - if (json.difficultyHybrid == null || json.difficultyHybrid == '') - $("#difficultyHybrid").html('-'); - else { - splitParts = json.difficultyHybrid.split('.'); - $("#difficultyHybrid").html(splitParts[0] + '.' + splitParts[1] + ''); - } - - showTopPanelData('difficultypanel', 'difficultyPanelLoading'); - - if (hashrateString == null || hashrateString == '' || hashrateString == '-') - $("#hashrate").html('-'); - else { - splitParts = hashrateString.split('.'); - $("#hashrate").html(splitParts[0] + '.' + splitParts[1] + ''); - } - showTopPanelData('hashratepanel', 'hashratePanelLoading'); - - splitValue = Number(json.lastPrice).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - splitParts = splitValue.split('.'); - $("#lastPrice").html(splitParts[0] + '.' + splitParts[1] + ''); - showTopPanelData('pricepanel', 'pricePanelLoading'); - } - - $("#lblConnections").text(json.connections + ' connections'); - $("#lblBlockcount").text(json.blockcount + ' blocks'); - }}); - } - var nethashChart; - var difficultyChart; - var countDecimals = function(value) { - let text = value.toString(); - - if (text.indexOf('e-') > -1) { - let [base, trail] = text.split('e-'); - let deg = parseInt(trail, 10); - return deg; - } else if (Math.floor(value) !== value) - return value.toString().split(".")[1].length || 0; - else - return 0; - } - function update_network_charts() { - $.ajax({ - url: '/ext/getnetworkchartdata', - success: function(result) { - if (#{settings.network_history.enabled} == true && #{showNethashChart} == true && #{settings.shared_pages.page_header.network_charts.nethash_chart.enabled} == true && #{settings.shared_pages.show_hashrate} == true) { - const ctxNethash = document.getElementById('nethashChart').getContext('2d'); - - if (nethashChart == null) { - nethashChart = new Chart(ctxNethash, { - type: 'line', - data: { - labels: result.map(function(a) {return a.blockindex;}), - datasets: [ - { - label: 'Hashrate', - data: result.map(function(a) {return a.nethash;}), - backgroundColor: ['#{settings.shared_pages.page_header.network_charts.nethash_chart.fill_color}'], - borderColor: ['#{settings.shared_pages.page_header.network_charts.nethash_chart.line_color}'], - fill: 'start' - } - ] - }, - options: { - maintainAspectRatio: false, - elements: { - point: { - radius: 1 - }, - line: { - tension: 0.1 - } - }, - scales: { - y: { - title: { - display: true, - text: 'Network ' + getNetHashUnits(), - font: { - weight: 'bold' - } - } - } - }, - plugins: { - legend: { - display: true, - position: 'bottom' - }, - title: { - display: false - }, - tooltip: { - mode: 'index', - intersect: false, - displayColors: true, - callbacks: { - title: function(context) { - return 'Block ' + context[0].label + ' Hashrate'; - }, - label: function(context) { - var val = #{settings.shared_pages.page_header.network_charts.nethash_chart.round_decimals}; - var max = 20; - - if (val != -1) - max = val; - else { - let decimalCount = countDecimals(context.raw || 0); - - if (decimalCount < max) - max = decimalCount; - } - - return Number((context.raw || 0)).toLocaleString('en',{'minimumFractionDigits':0,'maximumFractionDigits':max,'useGrouping':true}) + ' ' + getNetHashUnits(); - } - } - }, - crosshair: { - line: { - color: '#{settings.shared_pages.page_header.network_charts.nethash_chart.crosshair_color}', - width: 1 - }, - sync: { - enabled: false - }, - zoom: { - enabled: false - } - } - } - } - }); - $('#nethashChartParent').fadeIn(); - } else { - nethashChart.data.labels = result.map(function(a) {return a.blockindex;}); - nethashChart.data.datasets[0].data = result.map(function(a) {return a.nethash;}); - nethashChart.update(); - } - } - - if (#{settings.network_history.enabled} == true && #{showDifficultyChart} == true && #{settings.shared_pages.page_header.network_charts.difficulty_chart.enabled} == true) { - const ctxDifficulty = document.getElementById('difficultyChart').getContext('2d'); - - var diffDataSets = []; - var showPOW = false; - var showPOS = false; - - for (var i = 0; i < result.length; i++) { - if (result[i].difficulty_pow != 0) - showPOW = true; - if (result[i].difficulty_pos != 0) - showPOS = true; - } - - if (showPOS) { - diffDataSets.push({ - label: 'POS Difficulty', - data: result.map(function(a) {return a.difficulty_pos;}), - backgroundColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pos_fill_color}'], - borderColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pos_line_color}'], - fill: 'start' - }); - } - - if (showPOW || !showPOS) { - diffDataSets.push({ - label: 'POW Difficulty', - data: result.map(function(a) {return a.difficulty_pow;}), - backgroundColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pow_fill_color}'], - borderColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pow_line_color}'], - fill: 'start' - }); - } - - if (difficultyChart == null) { - difficultyChart = new Chart(ctxDifficulty, { - type: 'line', - data: { - labels: result.map(function(a) {return a.blockindex;}), - datasets: diffDataSets - }, - options: { - maintainAspectRatio: false, - elements: { - point: { - radius: 1 - }, - line: { - tension: 0.1 - } - }, - scales: { - y: { - title: { - display: true, - text: 'Difficulty', - font: { - weight: 'bold' - } - } - } - }, - plugins: { - legend: { - display: true, - position: 'bottom' - }, - title: { - display: false - }, - tooltip: { - mode: 'index', - intersect: false, - displayColors: true, - callbacks: { - title: function(context) { - return 'Block ' + context[0].label + ' Difficulty'; - }, - label: function(context) { - var val = #{settings.shared_pages.page_header.network_charts.difficulty_chart.round_decimals}; - var max = 20; - - if (val != -1) - max = val; - else { - let decimalCount = countDecimals(context.raw || 0); - - if (decimalCount < max) - max = decimalCount; - } - - return Number((context.raw || 0)).toLocaleString('en',{'minimumFractionDigits':0,'maximumFractionDigits':max,'useGrouping':true}); - } - } - }, - crosshair: { - line: { - color: '#{settings.shared_pages.page_header.network_charts.difficulty_chart.crosshair_color}', - width: 1 - }, - sync: { - enabled: false - }, - zoom: { - enabled: false - } - } - } - } - }); - $('#difficultyChartParent').fadeIn(); - } else { - difficultyChart.data.labels = result.map(function(a) {return a.blockindex;}); - - if (difficultyChart.data.datasets.length != diffDataSets.length) - difficultyChart.data.datasets = diffDataSets; - else { - if ( - ( - difficultyChart.data.datasets[0].label.indexOf('POW') > -1 && - diffDataSets[0].label.indexOf('POW') > -1 - ) - || - ( - difficultyChart.data.datasets[0].label.indexOf('POS') > -1 && - diffDataSets[0].label.indexOf('POS') > -1 - ) - ) { - difficultyChart.data.datasets[0].data = diffDataSets[0].data; - - if (difficultyChart.data.datasets.length == 2) - difficultyChart.data.datasets[1].data = diffDataSets[1].data; - } else - difficultyChart.data.datasets = diffDataSets; - } - - difficultyChart.update(); - } - } - } - }); - } - $(window).resize(function () { - fixDataTableColumns(); - fixFooterHeightAndPosition(); - - if ('#{settings.shared_pages.page_header.menu}' == 'side') { - fixSidebar(); - positionSidebarSearch(); - } else { - if ($(window).outerWidth() < 992) - hideMarketDropdown(); - - fixTopMenuCollapse(true); - } - }); function getNetworkPanel() { - var hashRateType=''; - return '
#{settings.locale.network} '+getNetHashUnits()+'
'; + return '
#{settings.locale.network} ' + getNetHashUnits() + '
'; } function getDifficultyPanel() { - var difficultyType=''; + let difficultyType=''; if ('#{settings.shared_pages.difficulty}' == 'Hybrid') difficultyType+='
'; return '
#{settings.locale.difficulty}
'; } @@ -668,12 +303,10 @@ html(lang='en') return '
#{settings.locale.masternodecount}
'; } function getCoinSupplyPanel() { - var supplyType=''; - return `
#{settings.locale.ex_supply} (${"#{settings.coin.symbol}".replace(/"/g, '"')})
`; + return `
#{settings.locale.ex_supply} (${"#{settings.coin.symbol}".replace(/"/g, '"')})
`; } function getPricePanel() { - var priceType=''; - return '
Price (#{settings.markets_page.default_exchange.trading_pair.split('/')[1]})
'; + return '
Price (#{settings.markets_page.default_exchange.trading_pair.split('/')[1]})
'; } function getMarketCapPanel() { return '
Market Cap (#{settings.markets_page.default_exchange.trading_pair.split('/')[1]})
'; @@ -685,298 +318,638 @@ html(lang='en') return `
`; } function getActivePanel(panelName) { - var sReturn=''; + let sReturn = ''; + switch (panelName) { case "network_panel": - sReturn=getNetworkPanel(); + sReturn = getNetworkPanel(); break; case "difficulty_panel": - sReturn=getDifficultyPanel(); + sReturn = getDifficultyPanel(); break; case "masternodes_panel": - sReturn=getMasternodesPanel(); + sReturn = getMasternodesPanel(); break; case "coin_supply_panel": - sReturn=getCoinSupplyPanel(); + sReturn = getCoinSupplyPanel(); break; case "price_panel": - sReturn=getPricePanel(); + sReturn = getPricePanel(); break; case "market_cap_panel": - sReturn=getMarketCapPanel(); + sReturn = getMarketCapPanel(); break; case "logo_panel": - sReturn=getLogoPanel(); + sReturn = getLogoPanel(); break; case "spacer_panel_1": case "spacer_panel_2": case "spacer_panel_3": - sReturn=getSpacerPanel(); + sReturn = getSpacerPanel(); break; } + return sReturn; } function hideShowPanel(panelID, panelName) { - var oPanel = document.getElementById(panelName); + const oPanel = document.getElementById(panelName); + if (typeof(oPanel) != 'undefined' && oPanel != null) { - document.getElementById(panelName).innerHTML=getActivePanel(panelID); + document.getElementById(panelName).innerHTML = getActivePanel(panelID); if (panelID == 'logo_panel') { - // Remove css classes from logo panel + // remove css classes from logo panel $(oPanel).removeClass(); } } } - function hideMarketDropdown() { - if ('#{settings.shared_pages.page_header.menu}' == 'side') { - if ($('div#side-market-menu').hasClass('show')) { - // close the market dropdown which was left open - bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).hide(); - } - } else { - if ($('li#markets > div.dropdown-menu').hasClass('show')) { - // close the market dropdown which was left open - bootstrap.Dropdown.getOrCreateInstance($('li#markets > a.dropdown-toggle')).hide(); - } - } - } - $(document).on('click', 'button.btn-close', function (e) { - e.preventDefault(); + function update_stats() { + const summary_headers = { + Accept: 'application/json, text/javascript, */*; q=0.01' + }; - $('.alert-dismissible').on('closed.bs.alert', function (e) { - e.preventDefault(); - fixFooterHeightAndPosition(); - }); - }); - $(document).on('click', 'button#search-header-button', function (e) { - if ($().tooltip) - $('#search-header-span').tooltip('hide'); - }); - $('#search-navbar-collapse').on('shown.bs.collapse', function (e) { - fixFooterHeightAndPosition(); - }); - $('#search-navbar-collapse').on('hidden.bs.collapse', function (e) { - fixFooterHeightAndPosition(); - }); - if (#{showPanels} == true) { + $.ajax({url: '/ext/getsummary', headers: summary_headers, success: function(json) { + if (json.masternodeCountOnline == null) + json.masternodeCountOnline = '-'; + if (json.masternodeCountOffline == null) + json.masternodeCountOffline = '-'; + + const mnOnlineText = json.masternodeCountOnline + " node"+(json.masternodeCountOnline == 1 ? "" : "s") + " online"; + const mnOfflineText = json.masternodeCountOffline + " unreachable node" + (json.masternodeCountOffline == 1 ? "" : "s"); + + $("#masternodeCountOnline").text(json.masternodeCountOnline).prop("alt", mnOnlineText).prop("title", mnOnlineText).attr("data-bs-original-title", mnOnlineText); + $("#masternodeCountOffline").text(json.masternodeCountOffline).prop("alt", mnOfflineText).prop("title", mnOfflineText).attr("data-bs-original-title", mnOfflineText); + $("#spnMasternodeCountOnline").prop("alt", mnOnlineText).prop("title", mnOnlineText).attr("data-bs-original-title", mnOnlineText); + $("#spnMasternodeCountOffline").prop("alt", mnOfflineText).prop("title", mnOfflineText).attr("data-bs-original-title", mnOfflineText); + showTopPanelData('masternodepanel', 'masternodePanelLoading'); + + let supplyString = json.supply; + let diffString = json.difficulty; + let hashrateString = json.hashrate; + let splitValue, splitParts; + + if (!isNaN(json.difficulty)) + diffString = Number(json.difficulty).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + if (!isNaN(json.supply)) + supplyString = parseInt(parseFloat(json.supply).toFixed(0)).toLocaleString('en'); + if (!isNaN(json.hashrate)) + hashrateString = Number(json.hashrate).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + + $("#supply").text(supplyString); + splitValue = Number(parseFloat(json.lastPrice).toFixed(8) * parseInt(parseFloat(json.supply).toFixed(0))).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + splitParts = splitValue.split('.'); + showTopPanelData('supplypanel', 'supplyPanelLoading'); + + $("#marketCap").html(splitParts[0] + '.' + splitParts[1] + ''); + showTopPanelData('marketCapPanel', 'marketCapPanelLoading'); + + splitParts = diffString.split('.'); + $("#difficulty").html(splitParts[0] + '.' + splitParts[1] + ''); + + if (json.difficultyHybrid == null || json.difficultyHybrid == '') + $("#difficultyHybrid").html('-'); + else { + splitParts = json.difficultyHybrid.split('.'); + $("#difficultyHybrid").html(splitParts[0] + '.' + splitParts[1] + ''); + } + + showTopPanelData('difficultypanel', 'difficultyPanelLoading'); + + if (hashrateString == null || hashrateString == '' || hashrateString == '-') + $("#hashrate").html('-'); + else { + splitParts = hashrateString.split('.'); + $("#hashrate").html(splitParts[0] + '.' + splitParts[1] + ''); + } + showTopPanelData('hashratepanel', 'hashratePanelLoading'); + + splitValue = Number(json.lastPrice).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + splitParts = splitValue.split('.'); + $("#lastPrice").html(splitParts[0] + '.' + splitParts[1] + ''); + showTopPanelData('pricepanel', 'pricePanelLoading'); + }}); + } + $(document).ready(function() { hideShowPanel('#{settings.panel1}', 'pnlOne'); hideShowPanel('#{settings.panel2}', 'pnlTwo'); hideShowPanel('#{settings.panel3}', 'pnlThree'); hideShowPanel('#{settings.panel4}', 'pnlFour'); hideShowPanel('#{settings.panel5}', 'pnlFive'); + + setInterval(function() { + update_stats(); + }, 60000); + + update_stats(); + }); + if settings.network_history.enabled == true && ((showNethashChart == true && settings.shared_pages.page_header.network_charts.nethash_chart.enabled == true && settings.shared_pages.show_hashrate == true) || (showDifficultyChart == true && settings.shared_pages.page_header.network_charts.difficulty_chart.enabled == true)) + script. + const countDecimals = function(value) { + const text = value.toString(); + + if (text.indexOf('e-') > -1) { + return parseInt(text.split('e-'), 10); + } else if (Math.floor(value) !== value) + return value.toString().split(".")[1].length || 0; + else + return 0; } - if ('#{settings.shared_pages.page_header.menu}' == 'side') { - function positionSidebarSearch() { - if (#{settings.shared_pages.page_header.search.enabled} == true && '#{settings.shared_pages.page_header.search.position.toString().toLowerCase()}' == 'inside-header') { - if ($(window).outerWidth() < 992) { - if ($('div#inner-header-side > div.container > div#search-navbar-collapse').length) - $('div#search-navbar-collapse').addClass('collapse').removeClass('flexGrow1').appendTo('header#main-header-side'); - } else { - if ($('header#main-header-side > div#search-navbar-collapse').length) - $('div#search-navbar-collapse').addClass('flexGrow1').removeClass('collapse').appendTo('div#inner-header-side > div.container'); - } + function update_network_charts() { + $.ajax({ + url: '/ext/getnetworkchartdata', + success: function(result) { + if (typeof populateNethashChart !== 'undefined' && typeof populateNethashChart === 'function') + populateNethashChart(result); + + if (typeof populateDifficultyChart !== 'undefined' && typeof populateDifficultyChart === 'function') + populateDifficultyChart(result); } + }); + } + $(document).ready(function() { + const setting_reload_chart_seconds = #{settings.shared_pages.page_header.network_charts.reload_chart_seconds}; + + if (setting_reload_chart_seconds > 0) { + setInterval(function() { + update_network_charts(); + }, (setting_reload_chart_seconds * 1000)); } - function fixSideBarTop() { - if ('#{settings.shared_pages.page_header.sticky_header}' == 'true') { - if ($(window).outerWidth() < 992) - $('div#side-nav-bar').css('margin-top', ''); - else - $('div#side-nav-bar').css('margin-top', $('header#main-header-side').outerHeight(true).toString() + 'px'); + + update_network_charts(); + }); + if settings.network_history.enabled == true && showNethashChart == true && settings.shared_pages.page_header.network_charts.nethash_chart.enabled == true && settings.shared_pages.show_hashrate == true + script. + let nethashChart; + + function populateNethashChart(result) { + const ctxNethash = document.getElementById('nethashChart').getContext('2d'); + + if (nethashChart == null) { + nethashChart = new Chart(ctxNethash, { + type: 'line', + data: { + labels: result.map(function(a) {return a.blockindex;}), + datasets: [ + { + label: 'Hashrate', + data: result.map(function(a) {return a.nethash;}), + backgroundColor: ['#{settings.shared_pages.page_header.network_charts.nethash_chart.fill_color}'], + borderColor: ['#{settings.shared_pages.page_header.network_charts.nethash_chart.line_color}'], + fill: 'start' + } + ] + }, + options: { + maintainAspectRatio: false, + elements: { + point: { + radius: 1 + }, + line: { + tension: 0.1 + } + }, + scales: { + y: { + title: { + display: true, + text: 'Network ' + getNetHashUnits(), + font: { + weight: 'bold' + } + } + } + }, + plugins: { + legend: { + display: true, + position: 'bottom' + }, + title: { + display: false + }, + tooltip: { + mode: 'index', + intersect: false, + displayColors: true, + callbacks: { + title: function(context) { + return 'Block ' + context[0].label + ' Hashrate'; + }, + label: function(context) { + const val = #{settings.shared_pages.page_header.network_charts.nethash_chart.round_decimals}; + let max = 20; + + if (val != -1) + max = val; + else { + const decimalCount = countDecimals(context.raw || 0); + + if (decimalCount < max) + max = decimalCount; + } + + return Number((context.raw || 0)).toLocaleString('en',{'minimumFractionDigits':0,'maximumFractionDigits':max,'useGrouping':true}) + ' ' + getNetHashUnits(); + } + } + }, + crosshair: { + line: { + color: '#{settings.shared_pages.page_header.network_charts.nethash_chart.crosshair_color}', + width: 1 + }, + sync: { + enabled: false + }, + zoom: { + enabled: false + } + } + } + } + }); + $('#nethashChartParent').fadeIn(); + } else { + nethashChart.data.labels = result.map(function(a) {return a.blockindex;}); + nethashChart.data.datasets[0].data = result.map(function(a) {return a.nethash;}); + nethashChart.update(); + } + } + if settings.network_history.enabled == true && showDifficultyChart == true && settings.shared_pages.page_header.network_charts.difficulty_chart.enabled == true + script. + let difficultyChart; + + function populateDifficultyChart(result) { + const ctxDifficulty = document.getElementById('difficultyChart').getContext('2d'); + + let diffDataSets = []; + let showPOW = false; + let showPOS = false; + + for (let i = 0; i < result.length; i++) { + if (result[i].difficulty_pow != 0) + showPOW = true; + if (result[i].difficulty_pos != 0) + showPOS = true; + } + + if (showPOS) { + diffDataSets.push({ + label: 'POS Difficulty', + data: result.map(function(a) {return a.difficulty_pos;}), + backgroundColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pos_fill_color}'], + borderColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pos_line_color}'], + fill: 'start' + }); + } + + if (showPOW || !showPOS) { + diffDataSets.push({ + label: 'POW Difficulty', + data: result.map(function(a) {return a.difficulty_pow;}), + backgroundColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pow_fill_color}'], + borderColor: ['#{settings.shared_pages.page_header.network_charts.difficulty_chart.pow_line_color}'], + fill: 'start' + }); + } + + if (difficultyChart == null) { + difficultyChart = new Chart(ctxDifficulty, { + type: 'line', + data: { + labels: result.map(function(a) {return a.blockindex;}), + datasets: diffDataSets + }, + options: { + maintainAspectRatio: false, + elements: { + point: { + radius: 1 + }, + line: { + tension: 0.1 + } + }, + scales: { + y: { + title: { + display: true, + text: 'Difficulty', + font: { + weight: 'bold' + } + } + } + }, + plugins: { + legend: { + display: true, + position: 'bottom' + }, + title: { + display: false + }, + tooltip: { + mode: 'index', + intersect: false, + displayColors: true, + callbacks: { + title: function(context) { + return 'Block ' + context[0].label + ' Difficulty'; + }, + label: function(context) { + const val = #{settings.shared_pages.page_header.network_charts.difficulty_chart.round_decimals}; + let max = 20; + + if (val != -1) + max = val; + else { + const decimalCount = countDecimals(context.raw || 0); + + if (decimalCount < max) + max = decimalCount; + } + + return Number((context.raw || 0)).toLocaleString('en',{'minimumFractionDigits':0,'maximumFractionDigits':max,'useGrouping':true}); + } + } + }, + crosshair: { + line: { + color: '#{settings.shared_pages.page_header.network_charts.difficulty_chart.crosshair_color}', + width: 1 + }, + sync: { + enabled: false + }, + zoom: { + enabled: false + } + } + } + } + }); + $('#difficultyChartParent').fadeIn(); + } else { + difficultyChart.data.labels = result.map(function(a) {return a.blockindex;}); + + if (difficultyChart.data.datasets.length != diffDataSets.length) + difficultyChart.data.datasets = diffDataSets; + else if ( + ( + difficultyChart.data.datasets[0].label.indexOf('POW') > -1 && + diffDataSets[0].label.indexOf('POW') > -1 + ) + || + ( + difficultyChart.data.datasets[0].label.indexOf('POS') > -1 && + diffDataSets[0].label.indexOf('POS') > -1 + ) + ) { + difficultyChart.data.datasets[0].data = diffDataSets[0].data; + + if (difficultyChart.data.datasets.length == 2) + difficultyChart.data.datasets[1].data = diffDataSets[1].data; } else - $('div#side-nav-bar').css('margin-top', '0'); + difficultyChart.data.datasets = diffDataSets; + + difficultyChart.update(); } - function fixSidebar() { + } + if (showPanels == true && showNetworkPanel == true) || (settings.network_history.enabled == true && showNethashChart == true && settings.shared_pages.page_header.network_charts.nethash_chart.enabled == true && settings.shared_pages.show_hashrate == true) + script. + function getNetHashUnits() { + let networkSuffix = ''; + + switch ('#{settings.shared_pages.page_header.panels.network_panel.nethash_units}') { + case "K": + networkSuffix='(KH/s)'; + break; + case "M": + networkSuffix='(MH/s)'; + break; + case "G": + networkSuffix='(GH/s)'; + break; + case "T": + networkSuffix='(TH/s)'; + break; + case "P": + networkSuffix='(PH/s)'; + break; + case "H": + networkSuffix='(H/s)'; + break; + } + + return networkSuffix; + } + if settings.shared_pages.page_header.menu == 'side' + script. + let sideMarketVisible = false; + const sideBarClasses = '!{sideBarClasses}'.replace(/,/g, " "); + + function fixSidebarHeight() { + if ('#{settings.shared_pages.page_footer.sticky_footer}' != 'true') + $('div#side-nav-bar').css('margin-bottom', -($('div#body-container > div#side-nav-bar').length ? ($('div#footer-container').offset().top - $('div#footer-container').position().top + 1) : 0).toString() + 'px'); + else if ($('div#footer-container').offset().top > ($('#main-container').position().top + $('#main-container').outerHeight(true))) + $('div#side-nav-bar').css('margin-bottom', -($('div#body-container > div#side-nav-bar').length ? ($('div#footer-container').offset().top - ($('#main-container').position().top + $('#main-container').outerHeight(true)) + $('div#footer-container').outerHeight(true)) : 0).toString() + 'px'); + else + $('div#side-nav-bar').css('margin-bottom', ''); + } + function hideMarketDropdown() { + if ($('div#side-market-menu').hasClass('show')) { + // close the market dropdown which was left open + bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).hide(); + } + } + function positionSidebarSearch() { + if (#{settings.shared_pages.page_header.search.enabled} == true && '#{settings.shared_pages.page_header.search.position.toString().toLowerCase()}' == 'inside-header') { if ($(window).outerWidth() < 992) { - if ($('div#side-nav-bar').hasClass('show-menu')) - toggleSideMenu(); - - if ($('div#body-container > div#side-nav-bar').length > 0) { - let hasScrollbar = false; - $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').show(); - $('nav.side-nav').css('overflow', 'visible'); - $('div#side-nav-bar').removeClass(sideBarClasses); - - if ($('div#side-offcanvas > div.offcanvas-body > div[data-overlayscrollbars-viewport="scrollbarHidden"]').length > 0) { - $('div#body-container > div#side-nav-bar').appendTo('div#side-offcanvas > div.offcanvas-body > div[data-overlayscrollbars-viewport="scrollbarHidden"]'); - hasScrollbar = true; - } else - $('div#body-container > div#side-nav-bar').appendTo('div#side-offcanvas > div.offcanvas-body'); - - hideMarketDropdown(); - $('a#side-header-toggle').attr('data-bs-toggle', 'offcanvas').attr('data-bs-target', '#side-offcanvas').attr('aria-controls', 'side-offcanvas'); - if ($().tooltip) - $('nav.side-nav li.nav-item').tooltip('disable'); - $('li.side-market-menu').removeClass('dropend').addClass('dropdown'); - $('li.side-market-menu > a.nav-link').attr('data-bs-toggle', 'collapse').attr('data-bs-target', '#side-market-menu').attr('aria-controls', '#side-market-menu').attr('aria-expanded', 'false'); - $('div#side-market-menu').removeClass('dropdown-menu dropdown-menu-dark').addClass('collapse'); - - if (!hasScrollbar) - OverlayScrollbars($('div#side-offcanvas > div.offcanvas-body')[0], {overflow: {x: 'hidden'}}); - - fixSidebarHeight(); - } + if ($('div#inner-header-side > div.container > div#search-navbar-collapse').length) + $('div#search-navbar-collapse').addClass('collapse').removeClass('flexGrow1').appendTo('header#main-header-side'); } else { - if ($('div#side-offcanvas > div.offcanvas-body div#side-nav-bar').length > 0) { - if ($('div#side-market-menu').hasClass('show')) { - // close the market collapse which was left open - bootstrap.Collapse.getOrCreateInstance($('#side-market-menu')).hide(); - } - - if ($('div#side-offcanvas').hasClass('show')) { - // close the offcanvas side-menu which was left open - bootstrap.Offcanvas.getOrCreateInstance($('div#side-offcanvas')).hide(); - } - - resetSideBarWidth(); - $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').hide(); - $('div#side-nav-bar').addClass(sideBarClasses); - $('div#side-offcanvas > div.offcanvas-body div#side-nav-bar').prependTo('div#body-container'); - $('a#side-header-toggle').removeAttr('data-bs-toggle').removeAttr('data-bs-target').removeAttr('aria-controls'); - if ($().tooltip) - $('nav.side-nav li.nav-item').tooltip('enable'); - $('li.side-market-menu').removeClass('dropdown').addClass('dropend'); - $('li.side-market-menu > a.nav-link').removeAttr('data-bs-toggle').removeAttr('data-bs-target').removeAttr('aria-controls').removeAttr('aria-expanded'); - $('div#side-market-menu').removeClass('collapse').addClass('dropdown-menu' + ('#{settings.shared_pages.page_header.bgcolor}' == null || '#{settings.shared_pages.page_header.bgcolor}' == 'null' || '#{settings.shared_pages.page_header.bgcolor}' == '' || '#{settings.shared_pages.page_header.bgcolor}'.toLowerCase() == 'dark' ? ' dropdown-menu-dark' : '')); - fixSidebarHeight(); - } - } - - fixSideBarTop(); - } - function toggleSideMenu() { - if (!$('div#side-nav-bar').hasClass('activating')) { - $('div#side-nav-bar').toggleClass('activating'); - $('div#side-nav-bar').toggleClass('show-menu'); - var showMenu = $('div#side-nav-bar').hasClass('show-menu'); - $('a#side-header-toggle > span').toggleClass('fa-regular fa-solid fa-rectangle-xmark fa-bars').attr('data-bs-original-title', (showMenu ? 'Shrink Menu' : 'Expand Menu')).attr('alt', (showMenu ? 'Shrink Menu' : 'Expand Menu')); - hideMarketDropdown(); - - if ($().tooltip) { - $('a#side-header-toggle > span').tooltip('hide'); - $('nav.side-nav li.nav-item').tooltip((showMenu ? 'disable' : 'enable')); - } - - $('nav.side-nav').css('overflow', 'hidden'); - - if (showMenu) - $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').show(); - - // wait for the side bar to reach the desired width - var sideBarActivateSetIntervalID = setInterval(function() { - // check if the side bar has reached the full width or menu has been activated before finish - if ( - (showMenu && Math.round($('div#side-nav-bar').outerWidth()) >= 224) || - (!showMenu && Math.round($('div#side-nav-bar').outerWidth()) <= 68) || - (showMenu != $('div#side-nav-bar').hasClass('show-menu')) - ) { - // stop setInterval from running again - clearInterval(sideBarActivateSetIntervalID); - $('div#side-nav-bar').toggleClass('activating'); - - if (!showMenu) - $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').hide(); - - $('nav.side-nav').css('overflow', 'visible'); - - // programatically call the resize event - $(window).trigger('resize'); - } - }, 1, "tmrWaitActivateSideMenu"); + if ($('header#main-header-side > div#search-navbar-collapse').length) + $('div#search-navbar-collapse').addClass('flexGrow1').removeClass('collapse').appendTo('div#inner-header-side > div.container'); } } - function resetSideBarWidth() { - $('div#side-offcanvas').css('width', ''); - $('div#side-nav-bar').css('width', ''); - } - $(document).on('click', 'a#side-header-toggle', function(e) { - e.preventDefault(); - - if ($(window).outerWidth() >= 992) + } + function fixSideBarTop() { + if ('#{settings.shared_pages.page_header.sticky_header}' == 'true') { + if ($(window).outerWidth() < 992) + $('div#side-nav-bar').css('margin-top', ''); + else + $('div#side-nav-bar').css('margin-top', $('header#main-header-side').outerHeight(true).toString() + 'px'); + } else + $('div#side-nav-bar').css('margin-top', '0'); + } + function fixSidebar() { + if ($(window).outerWidth() < 992) { + if ($('div#side-nav-bar').hasClass('show-menu')) toggleSideMenu(); - else if ($().tooltip) - $('a#side-header-toggle > span').tooltip('hide'); - }); - $(document).on('click', 'li#sidebar-offcanvas-close > a.nav-link', function(e) { - e.preventDefault(); - - if ($().tooltip) - $('li#sidebar-offcanvas-close > a.nav-link').tooltip('hide'); - }); - $(document).on('click', 'li.side-market-menu', function(e) { - if ($().tooltip && !$('#side-nav-bar').hasClass('show-menu') && $(window).outerWidth() >= 992) - $('nav.side-nav li#markets.nav-item').tooltip('hide'); - }); - $(document).on('click', 'li.side-market-menu > a.dropdown-toggle', function(e) { - e.preventDefault(); if ($('div#body-container > div#side-nav-bar').length > 0) { - // manually set the positon of the market dropdown since botostrap disables popper when called from within a .navbar - $('#side-market-menu').css({ - 'position': 'absolute', - 'inset': 'auto auto 0px 0px', - 'margin': '0px', - 'transform': 'translate3d(' + e.pageX.toString() + 'px, 30px, 0px)' - }); + let hasScrollbar = false; - // programatically trigger the dropdown since controlling bs dropdowns via data attributes has some unintended consequences of - // keeping the popper attributes around too long in specific scenarios when changing screen size and the dropdown is left open - bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).toggle(); - } else { - if ($('li.side-market-menu > a.dropdown-toggle[aria-expanded="true"]').length > 0) { - const sideBarWidth = 226; - const normalItemWidth = 192; - const firstItem = $('div#side-market-menu > a.dropdown-item').first(); - const leftRightPadding = (firstItem == null ? 0 : parseFloat(firstItem.css('padding-right').replace('px', '')) + parseFloat(firstItem.css('margin-right').replace('px', ''))) * 2; - let largestItemWidth = 0; + $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').show(); + $('nav.side-nav').css('overflow', 'visible'); + $('div#side-nav-bar').removeClass(sideBarClasses); - // find the largest market item to see if the sidebar should be expanded even wider - $('div#side-market-menu > a.dropdown-item').each(function () { - let currentItemWidth = $(this).find('> img').outerWidth(true) + $(this).find('> span').outerWidth(true); - largestItemWidth = (currentItemWidth > largestItemWidth ? currentItemWidth : largestItemWidth); - }); - - if (largestItemWidth > (normalItemWidth - leftRightPadding)) { - $('div#side-offcanvas').css('width', (sideBarWidth + largestItemWidth - (normalItemWidth - leftRightPadding)).toString() + 'px'); - $('div#side-nav-bar').css('width', 'auto'); - } else - resetSideBarWidth(); + if ($('div#side-offcanvas > div.offcanvas-body > div[data-overlayscrollbars-viewport="scrollbarHidden"]').length > 0) { + $('div#body-container > div#side-nav-bar').appendTo('div#side-offcanvas > div.offcanvas-body > div[data-overlayscrollbars-viewport="scrollbarHidden"]'); + hasScrollbar = true; } else - resetSideBarWidth(); - } - }); - /* Add a click event for the whole document when markets are enabled to emulate the autoClose feature which doesn't work when controlling bootstrap dropdowns via javascript */ - if (#{settings.markets_page.enabled} == true && #{settings.markets_page.show_market_dropdown_menu} == true && #{settings.market_count} > 1) { - $(document).on('click', function(e) { - if (sideMarketVisible) - bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).hide(); - }); - $('li.side-market-menu > a.dropdown-toggle').on('shown.bs.dropdown', function (e) { + $('div#body-container > div#side-nav-bar').appendTo('div#side-offcanvas > div.offcanvas-body'); + + hideMarketDropdown(); + $('a#side-header-toggle').attr('data-bs-toggle', 'offcanvas').attr('data-bs-target', '#side-offcanvas').attr('aria-controls', 'side-offcanvas'); + if ($().tooltip) - $('li#markets.nav-item').tooltip('disable'); + $('nav.side-nav li.nav-item').tooltip('disable'); - // wait a tick before upating the sideMarketVisible value - setTimeout(function() { - sideMarketVisible = true; - }, 1); - }); - $('li.side-market-menu > a.dropdown-toggle').on('hidden.bs.dropdown', function (e) { - sideMarketVisible = false; + $('li.side-market-menu').removeClass('dropend').addClass('dropdown'); + $('li.side-market-menu > a.nav-link').attr('data-bs-toggle', 'collapse').attr('data-bs-target', '#side-market-menu').attr('aria-controls', '#side-market-menu').attr('aria-expanded', 'false'); + $('div#side-market-menu').removeClass('dropdown-menu dropdown-menu-dark').addClass('collapse'); - if ($().tooltip && !$('div#side-nav-bar').hasClass('show-menu')) - $('li#markets.nav-item').tooltip('enable'); + if (!hasScrollbar) + OverlayScrollbars($('div#side-offcanvas > div.offcanvas-body')[0], {overflow: {x: 'hidden'}}); - $('#side-market-menu').css({ - 'position': '', - 'inset': '', - 'margin': '', - 'transform': '' - }); - }); + fixSidebarHeight(); + } + } else if ($('div#side-offcanvas > div.offcanvas-body div#side-nav-bar').length > 0) { + if ($('div#side-market-menu').hasClass('show')) { + // close the market collapse which was left open + bootstrap.Collapse.getOrCreateInstance($('#side-market-menu')).hide(); + } + + if ($('div#side-offcanvas').hasClass('show')) { + // close the offcanvas side-menu which was left open + bootstrap.Offcanvas.getOrCreateInstance($('div#side-offcanvas')).hide(); + } + + resetSideBarWidth(); + $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').hide(); + $('div#side-nav-bar').addClass(sideBarClasses); + $('div#side-offcanvas > div.offcanvas-body div#side-nav-bar').prependTo('div#body-container'); + $('a#side-header-toggle').removeAttr('data-bs-toggle').removeAttr('data-bs-target').removeAttr('aria-controls'); + + if ($().tooltip) + $('nav.side-nav li.nav-item').tooltip('enable'); + + $('li.side-market-menu').removeClass('dropdown').addClass('dropend'); + $('li.side-market-menu > a.nav-link').removeAttr('data-bs-toggle').removeAttr('data-bs-target').removeAttr('aria-controls').removeAttr('aria-expanded'); + $('div#side-market-menu').removeClass('collapse').addClass('dropdown-menu' + ('#{settings.shared_pages.page_header.bgcolor}' == null || '#{settings.shared_pages.page_header.bgcolor}' == 'null' || '#{settings.shared_pages.page_header.bgcolor}' == '' || '#{settings.shared_pages.page_header.bgcolor}'.toLowerCase() == 'dark' ? ' dropdown-menu-dark' : '')); + + fixSidebarHeight(); } + + fixSideBarTop(); + } + function toggleSideMenu() { + if (!$('div#side-nav-bar').hasClass('activating')) { + $('div#side-nav-bar').toggleClass('activating'); + $('div#side-nav-bar').toggleClass('show-menu'); + + const showMenu = $('div#side-nav-bar').hasClass('show-menu'); + + $('a#side-header-toggle > span').toggleClass('fa-regular fa-solid fa-rectangle-xmark fa-bars').attr('data-bs-original-title', (showMenu ? 'Shrink Menu' : 'Expand Menu')).attr('alt', (showMenu ? 'Shrink Menu' : 'Expand Menu')); + hideMarketDropdown(); + + if ($().tooltip) { + $('a#side-header-toggle > span').tooltip('hide'); + $('nav.side-nav li.nav-item').tooltip((showMenu ? 'disable' : 'enable')); + } + + $('nav.side-nav').css('overflow', 'hidden'); + + if (showMenu) + $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').show(); + + // wait for the side bar to reach the desired width + let sideBarActivateSetIntervalID = setInterval(function() { + // check if the side bar has reached the full width or menu has been activated before finish + if ( + (showMenu && Math.round($('div#side-nav-bar').outerWidth()) >= 224) || + (!showMenu && Math.round($('div#side-nav-bar').outerWidth()) <= 68) || + (showMenu != $('div#side-nav-bar').hasClass('show-menu')) + ) { + // stop setInterval from running again + clearInterval(sideBarActivateSetIntervalID); + + $('div#side-nav-bar').toggleClass('activating'); + + if (!showMenu) + $('#side-nav-bar li.nav-item > a.nav-link > span:last-child').hide(); + + $('nav.side-nav').css('overflow', 'visible'); + + // programatically call the resize event + $(window).trigger('resize'); + } + }, 1, "tmrWaitActivateSideMenu"); + } + } + function resetSideBarWidth() { + $('div#side-offcanvas').css('width', ''); + $('div#side-nav-bar').css('width', ''); + } + $(document).on('click', 'a#side-header-toggle', function(e) { + e.preventDefault(); + + if ($(window).outerWidth() >= 992) + toggleSideMenu(); + else if ($().tooltip) + $('a#side-header-toggle > span').tooltip('hide'); + }); + $(document).on('click', 'li#sidebar-offcanvas-close > a.nav-link', function(e) { + e.preventDefault(); + + if ($().tooltip) + $('li#sidebar-offcanvas-close > a.nav-link').tooltip('hide'); + }); + $(window).resize(function () { fixSidebar(); positionSidebarSearch(); - } else { + }); + $(document).ready(function() { + fixSidebar(); + positionSidebarSearch(); + }); + else + script. + let topMenuExpanded = false; + + function fixTopMenuCollapse(isResizing) { + if (topMenuExpanded && isResizing) { + // force collapse the menu if it is open and the screen is being resized, + // otherwise it could cause problems with the market dropdown after resizing back and forth between mobile and desktop sizes + bootstrap.Collapse.getOrCreateInstance($('#navbar-collapse')).hide(); + topMenuExpanded = false; + } + + if ($().tooltip) + $('#navbar-toggler-span').tooltip('hide'); + + if (topMenuExpanded) { + $('#search-header-button').hide(); + $('#search-navbar-collapse').addClass('d-none'); + $('#navbar-collapse').css('max-height', ($(window).outerHeight() - ($('#main-header div.navbar-header').outerHeight()) - (#{settings.shared_pages.page_footer.sticky_footer} == true ? $('div#footer-container').outerHeight(true) : 0) - 20).toString() + 'px'); + } else + $('#navbar-collapse').css('max-height', 'none'); + } + function hideMarketDropdown() { + if ($('li#markets > div.dropdown-menu').hasClass('show')) { + // close the market dropdown which was left open + bootstrap.Dropdown.getOrCreateInstance($('li#markets > a.dropdown-toggle')).hide(); + } + } + $(window).resize(function () { + if ($(window).outerWidth() < 992) + hideMarketDropdown(); + + fixTopMenuCollapse(true); + }); + $(document).ready(function() { $('#navbar-collapse').on('show.bs.collapse', function (e) { topMenuExpanded = true; fixTopMenuCollapse(false); @@ -994,23 +967,80 @@ html(lang='en') $('#search-header-button').show(); $('#search-navbar-collapse').removeClass('d-none'); }); - } - setInterval(function() { - update_stats(); - }, 60000); - if (#{settings.network_history.enabled} == true && ((#{showNethashChart} == true && #{settings.shared_pages.page_header.network_charts.nethash_chart.enabled} == true && #{settings.shared_pages.show_hashrate} == true) || (#{showDifficultyChart} == true && #{settings.shared_pages.page_header.network_charts.difficulty_chart.enabled} == true))) { - var setting_reload_chart_seconds = #{settings.shared_pages.page_header.network_charts.reload_chart_seconds}; - if (setting_reload_chart_seconds > 0) { - setInterval(function() { - update_network_charts(); - }, (setting_reload_chart_seconds * 1000)); + }); + if settings.shared_pages.page_header.menu == 'side' && settings.markets_page.enabled == true && settings.markets_page.show_market_dropdown_menu == true && settings.market_count > 1 + script. + /* Add a click event for the whole document when markets are enabled to emulate the autoClose feature which doesn't work when controlling bootstrap dropdowns via javascript - More info: https://github.com/twbs/bootstrap/issues/37042 */ + $(document).on('click', function(e) { + if (sideMarketVisible) + bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).hide(); + }); + $(document).on('click', 'li.side-market-menu', function(e) { + if ($().tooltip && !$('#side-nav-bar').hasClass('show-menu') && $(window).outerWidth() >= 992) + $('nav.side-nav li#markets.nav-item').tooltip('hide'); + }); + $(document).on('click', 'li.side-market-menu > a.dropdown-toggle', function(e) { + e.preventDefault(); + + if ($('div#body-container > div#side-nav-bar').length > 0) { + // manually set the positon of the market dropdown since bootstrap disables popper when called from within a .navbar + $('#side-market-menu').css({ + 'position': 'absolute', + 'inset': 'auto auto 0px 0px', + 'margin': '0px', + 'transform': 'translate3d(' + e.pageX.toString() + 'px, 30px, 0px)' + }); + + // programatically trigger the dropdown since controlling bs dropdowns via data attributes has some unintended consequences of + // keeping the popper attributes around too long in specific scenarios when changing screen size and the dropdown is left open + bootstrap.Dropdown.getOrCreateInstance($('li.side-market-menu > a.dropdown-toggle')).toggle(); + } else { + if ($('li.side-market-menu > a.dropdown-toggle[aria-expanded="true"]').length > 0) { + const sideBarWidth = 226; + const normalItemWidth = 192; + const firstItem = $('div#side-market-menu > a.dropdown-item').first(); + const leftRightPadding = (firstItem == null ? 0 : parseFloat(firstItem.css('padding-right').replace('px', '')) + parseFloat(firstItem.css('margin-right').replace('px', ''))) * 2; + let largestItemWidth = 0; + + // find the largest market item to see if the sidebar should be expanded even wider + $('div#side-market-menu > a.dropdown-item').each(function () { + const currentItemWidth = $(this).find('> img').outerWidth(true) + $(this).find('> span').outerWidth(true); + largestItemWidth = (currentItemWidth > largestItemWidth ? currentItemWidth : largestItemWidth); + }); + + if (largestItemWidth > (normalItemWidth - leftRightPadding)) { + $('div#side-offcanvas').css('width', (sideBarWidth + largestItemWidth - (normalItemWidth - leftRightPadding)).toString() + 'px'); + $('div#side-nav-bar').css('width', 'auto'); + } else + resetSideBarWidth(); + } else + resetSideBarWidth(); } - update_network_charts(); - } - update_stats(); - fixFooterHeightAndPosition(); - enableTooltips(); - }); + }); + $(document).ready(function() { + $('li.side-market-menu > a.dropdown-toggle').on('shown.bs.dropdown', function (e) { + if ($().tooltip) + $('li#markets.nav-item').tooltip('disable'); + + // wait a tick before upating the sideMarketVisible value + setTimeout(function() { + sideMarketVisible = true; + }, 1); + }); + $('li.side-market-menu > a.dropdown-toggle').on('hidden.bs.dropdown', function (e) { + sideMarketVisible = false; + + if ($().tooltip && !$('div#side-nav-bar').hasClass('show-menu')) + $('li#markets.nav-item').tooltip('enable'); + + $('#side-market-menu').css({ + 'position': '', + 'inset': '', + 'margin': '', + 'transform': '' + }); + }); + }); - var bodyClasses = []; - var bodyContainerClasses = []; - var mainContainerClasses = []; diff --git a/views/richlist.pug b/views/richlist.pug index 12eabfd..99a58d1 100644 --- a/views/richlist.pug +++ b/views/richlist.pug @@ -2,7 +2,24 @@ extends layout block content include ./includes/common.pug + script. + $(document).ready(function() { + if ('#{settings.richlist_page.page_header.show_last_updated}' == 'true') { + var lastUpdatedDate = #{(last_updated == null || last_updated == '0' ? 0 : last_updated)}; + if (lastUpdatedDate != 0) { + $('span#lastUpdatedDate').html(' ' + format_unixtime(lastUpdatedDate)); + + if (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true) { + $('span#lastUpdatedDate').attr('data-bs-toggle', 'tooltip').attr('data-bs-placement', 'auto').attr('title', format_unixtime(lastUpdatedDate, true)); + enableTooltips(); + } + } else + $('span#lastUpdatedDate').html(' N/A'); + } + if (#{settings.shared_pages.page_header.page_title_image.enable_animation} == true && #{settings.richlist_page.page_header.show_img} == true) + startRotateElement('img#header-img'); + }); if settings.richlist_page.wealth_distribution.show_distribution_chart == true script. $(document).ready(function() { @@ -42,22 +59,6 @@ block content } } }); - - if ('#{settings.richlist_page.page_header.show_last_updated}' == 'true') { - var lastUpdatedDate = #{(last_updated == null || last_updated == '0' ? 0 : last_updated)}; - - if (lastUpdatedDate != 0) { - $('span#lastUpdatedDate').html(' ' + format_unixtime(lastUpdatedDate)); - - if (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true) { - $('span#lastUpdatedDate').attr('data-bs-toggle', 'tooltip').attr('data-bs-placement', 'auto').attr('title', format_unixtime(lastUpdatedDate, true)); - enableTooltips(); - } - } else - $('span#lastUpdatedDate').html(' N/A'); - } - if (#{settings.shared_pages.page_header.page_title_image.enable_animation} == true && #{settings.richlist_page.page_header.show_img} == true) - startRotateElement('img#header-img'); }); - var theadClasses = []; if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != ''