github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/www/resources/gocoin.js (about)

     1  const min_btc_addr_len = 27 // 1111111111111111111114oLvT2
     2  const b58set = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
     3  
     4  var prvpos = null
     5  
     6  
     7  function ajax() {
     8  	try { xmlHttp=new XMLHttpRequest(); }
     9  	catch (e) {
    10  		try { xmlHttp=new ActiveXObject("Msxml2.XMLHTTP"); }
    11  		catch (e) {
    12  			try { xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); }
    13  			catch (e) { alert("AJAX error!"); return null; }
    14  		}
    15  	}
    16  	return xmlHttp;
    17  }
    18  
    19  function xval(xml,tag) {
    20  	try {
    21  		return xml.getElementsByTagName(tag)[0].childNodes[0].nodeValue;
    22  	} catch (e) {
    23  		return null
    24  	}
    25  }
    26  
    27  function config(q) {
    28  	document.location = 'cfg?sid='+sid+'&'+q
    29  }
    30  
    31  function leftpad(v,c,n) {
    32  	v = v.toString()
    33  	while (v.length<n) v=c+v
    34  	return v
    35  }
    36  
    37  function rightpad(v,c,n) {
    38  	v = v.toString()
    39  	while (v.length<n) v=v+c
    40  	return v
    41  }
    42  
    43  function val2str_pad(val,pad) {
    44  	var i,neg
    45  	if (neg=(val<0)) val=-val
    46  	var frac = (val%1e8).toString()
    47  	while (frac.length<8) frac='0'+frac
    48  	if (pad) {
    49  		frac='.'+frac
    50  	} else {
    51  		for (i=8; i>0 && frac[i-1]=='0'; i--);
    52  		if (i!=8) {
    53  			if (i>0) frac='.'+frac.substr(0,i)
    54  			else frac=''
    55  		} else frac='.'+frac
    56  	}
    57  	var btcs = Math.floor(val/1e8)
    58  	btcs=btcs.toString()+frac
    59  	return neg?('-'+btcs):btcs
    60  }
    61  
    62  function val2str(val) {
    63  	return val2str_pad(val,false)
    64  }
    65  
    66  function val2int(str) {
    67  	var ss=str.split('.')
    68  	if (ss.length==1) {
    69  		return parseInt(ss[0])*1e8
    70  	} else if (ss.length==2) {
    71  		if (ss[1].length>8) return Number.NaN
    72  		while (ss[1].length<8) ss[1]+='0'
    73  		return parseInt(ss[0])*1e8 + parseInt(ss[1])
    74  	}
    75  	return Number.NaN
    76  }
    77  
    78  function tim2str(tim, timeonly) {
    79  	var d = new Date(tim*1000)
    80  	//var timeonly=false
    81  	var res = ''
    82  	if (!timeonly) {
    83  		res += d.getFullYear() + "/" + leftpad(d.getMonth()+1, "0", 2) + "/" + leftpad(d.getDate(), "0", 2) + ' '
    84  	}
    85  	res += leftpad(d.getHours(), "0", 2) + ":" + leftpad(d.getMinutes(), "0", 2) + ":" + leftpad(d.getSeconds(), "0", 2)
    86  	return res
    87  }
    88  
    89  function pushtx() {
    90  	var rawtx = prompt("Enter raw transaction data (hexdump)")
    91  	if (rawtx!=null) {
    92  		var form = document.createElement("form")
    93  		form.setAttribute("method", "post")
    94  		form.setAttribute("action", "txs")
    95  		var rtx = document.createElement("input")
    96  		rtx.setAttribute("type", "hidden")
    97  		rtx.setAttribute("name", "rawtx")
    98  		rtx.setAttribute("value", rawtx)
    99  		form.appendChild(rtx)
   100  		document.body.appendChild(form)
   101  		form.submit()
   102  	}
   103  }
   104  
   105  function savecfg() {
   106  	document.location='/cfg?savecfg&sid='+sid
   107  }
   108  
   109  function bignum(n) {
   110  	if (n<10e3) {
   111  		if ((n%1)===0) {
   112  			return n + ' '
   113  		}
   114  		return n.toFixed(1) + " "
   115  	}
   116  	if (n<10e6) {
   117  		return (n/1e3).toFixed(1) + " K"
   118  	}
   119  	if (n<10e9) {
   120  		return (n/1e6).toFixed(1) + " M"
   121  	}
   122  	if (n<10e12) {
   123  		return (n/1e9).toFixed(1) + " G"
   124  	}
   125  	if (n<10e15) {
   126  		return (n/1e12).toFixed(1) + " T"
   127  	}
   128  	if (n<10e18) {
   129  		return (n/1e15).toFixed(1) + " P"
   130  	}
   131  	if (n<10e21) {
   132  		return (n/1e18).toFixed(1) + " E"
   133  	}
   134  	if (n<10e24) {
   135  		return (n/1e21).toFixed(1) + " Z"
   136  	}
   137  	return (n/1e24).toFixed(2) + " Y"
   138  }
   139  
   140  function int2ip(i) {
   141  	var a = (i>>24)&255
   142  	var b = (i>>16)&255
   143  	var c = (i>>8)&255
   144  	var d = i&255
   145  	return a+'.'+b+'.'+c+'.'+d
   146  }
   147  
   148  function hex2array(t) {
   149  	if ((t.length & 1)==1) {
   150  		return null
   151  	}
   152  	var pkb = new Uint8Array(t.length/2)
   153  	for (var i = 0; i < t.length; i += 2) {
   154          var v = parseInt(t.substr(i, 2), 16)
   155  		if (isNaN(v)) return null
   156  		pkb[i/2] = v
   157  	}
   158  	return pkb
   159  }
   160  
   161  function valid_pubkey(s) {
   162  	if (s.length == 66 && (s.substr(0,2)=="02" || s.substr(0,2)=="03")) {
   163  		s = s.toLowerCase()
   164  		for (var i=0; i<s.length; i++) {
   165  			var c = s[i]
   166  			if (!(c >= '0' && c <= '9' || c >= 'a' && c <= 'f')) return false
   167  		}
   168  		return true
   169  	}
   170  	return false
   171  }
   172  
   173  function valid_bech32_addr(s) {
   174  	return (s.length == 62 || s.length==42) && (s.substr(0,3)=="bc1" || s.substr(0,3)=="tc1")
   175  }
   176  
   177  function valid_base58_addr(s) {
   178  	for (var i=0; i<s.length; s++) {
   179  		if (b58set.indexOf(s[i])==-1) {
   180  			return false
   181  		}
   182  	}
   183  	return true
   184  }
   185  
   186  function valid_btc_addr(s) {
   187  	try {
   188  		if (s.length<min_btc_addr_len) return false
   189  		if (s[0]=='#') return false
   190  		if (valid_pubkey(s))  return true
   191  		if (valid_bech32_addr(s))  return true
   192  		if (valid_base58_addr(s))  return true
   193  	} catch (e) {
   194  		console.log("valid_btc_addr:", e)
   195  		return false
   196  	}
   197  }
   198  
   199  function period2str(upsec) {
   200  	if (upsec<120) {
   201  		return upsec + ' sec'
   202  	}
   203  	var mins = upsec/60
   204  	if (mins<120) {
   205  		return mins.toFixed(1) + ' min'
   206  	}
   207  
   208  	var hrs = mins/60
   209  	if (hrs<48) {
   210  		return hrs.toFixed(1) + ' hours'
   211  	}
   212  
   213  	var days = hrs/24
   214  	return days.toFixed(1) + ' days'
   215  }
   216  
   217  function parse_wallet(s) {
   218  	var wallet = new Array()
   219  	try {
   220  		var cont = s.split('\n')
   221  		for (var i=0; i<cont.length; i++) {
   222  			var line = cont[i].trim()
   223  			var sp_idx = line.indexOf(' ')
   224  			var addr, label
   225  			if (sp_idx==-1) {
   226  				addr = line
   227  				label = ''
   228  			} else {
   229  				addr = line.substr(0, sp_idx)
   230  				label = line.substr(sp_idx+1)
   231  			}
   232  			if (valid_btc_addr(addr)) {
   233  				wallet.push({'addr':addr, 'label':label, 'virgin':cont[i][0]==' '})
   234  			}
   235  		}
   236  	} catch (e) {
   237  		console.log("parse_wallet:", e)
   238  	}
   239  	return wallet
   240  }
   241  
   242  function build_wallet_list() {
   243  	var gvi = localStorage.getItem("gocoinWalletId")
   244  	var i
   245  
   246  	var names = localStorage.getItem("gocoinWallets").split('|')
   247  	var s = ''
   248  	for (i=0; i<names.length; i++) {
   249  		if (names[i]!="") {
   250  			var content = localStorage.getItem("gocoinWal_"+names[i])
   251  			if (typeof(content)=="string" && content.length > 0) {
   252  				var o = document.createElement("option")
   253  				o.value = o.text = names[i]
   254  				qswal.add(o)
   255  				if (localStorage.getItem("gocoinWalletSelected")==names[i]) {
   256  					qswal.selectedIndex = qswal.length-1
   257  				}
   258  				if (s!='') s+='|'
   259  				s += names[i]
   260  			} else {
   261  				console.log("removing webwallet", names[i])
   262  				localStorage.removeItem("gocoinWal_"+names[i])
   263  			}
   264  		}
   265  	}
   266  	localStorage.setItem("gocoinWallets", s)
   267  }
   268  
   269  function quick_switch_wallet() {
   270  	try {
   271  		if (qswal.options.length==0 || qswal.selectedIndex<0 || qswal.options.length<=qswal.selectedIndex) return
   272  		var name = qswal.options[qswal.selectedIndex].text
   273  		localStorage.setItem("gocoinWalletSelected", name)
   274  		var e = document.createEvent("Event")
   275  		e.initEvent("loadwallet", false, false)
   276  		e.name = name
   277  		qswal.dispatchEvent(e)
   278  	} catch (e) {
   279  		console.log("quick_switch_wallet:", e)
   280  	}
   281  }
   282  
   283  function noscroll() {
   284  	scroll(0,0)
   285  }
   286  
   287  function closepopup_x(fees) {
   288  	if (light.style.display!='none') {
   289  		if (fees) {
   290  			$("#block_fees").unbind("plothover")
   291  			$("#fees_tooltip").remove()
   292  		}
   293  		light.style.display='none'
   294  		fade.style.display='none'
   295  		window.scrollTo(0,prvpos)
   296  		document.removeEventListener("scroll", noscroll)
   297  	}
   298  }
   299  
   300  function closepopup() {
   301  	closepopup_x(true)
   302  }
   303  
   304  function css(selector, property, value) {
   305  	for (var i=0; i<document.styleSheets.length;i++) {//Loop through all styles
   306  		//Try add rule
   307  		try {
   308  			document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length);
   309  		} catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE
   310  	}
   311  }
   312  
   313  
   314  var last_height // used for showing block fees
   315  var fees_plot_data = [ { data : [] } ];
   316  var previousPoint = null
   317  var max_spb, totbytes
   318  
   319  function show_fees_tooltip(x, y, contents) {
   320  	$('<div id="fees_tooltip">' + contents + '</div>').css( {
   321  		'position': 'absolute',
   322  		'display': 'none',
   323  		'top': y - 29,
   324  		'left': x + 4,
   325  		'text-align' : 'center',
   326  		'z-index': 9999,
   327  		'border': '2px solid green',
   328  		'padding': '5px',
   329  		'font-size' : '12px',
   330  		'background-color': '#c0c0c0',
   331  		'opacity': 1
   332  	}).appendTo("body").fadeIn(200);
   333  }
   334  
   335  function show_cursor_tooltip(x, y, contents) {
   336  	$('<div id="fees_tooltip">' + contents + '</div>').css( {
   337  		'position': 'absolute',
   338  		'display': 'none',
   339  		'top': y - 29,
   340  		'left': x + 4,
   341  		'text-align' : 'center',
   342  		'border': '1px solid black',
   343  		'z-index': 9999,
   344  		'padding': '3px',
   345  		'font-size' : '12px',
   346  		'background-color': 'white',
   347  		'color': 'rgba(170, 0, 0, 0.80)',
   348  		'opacity': 1
   349  	}).appendTo("body").fadeIn(200);
   350  }
   351  
   352  function show_fees_handlehover(event, pos, item) {
   353  	if (item) {
   354  		if (previousPoint != item.dataIndex) {
   355  			var rec = fees_plot_data[0].data[item.dataIndex]
   356  			previousPoint = item.dataIndex
   357  			$("#fees_tooltip").remove()
   358  			var str = '<b>' + parseFloat(rec[1]).toFixed(2) + '</b> SPB at ' +
   359  				'<b>' + (100.0*rec[0]/1e6).toFixed(0) + '%</b><br>(of max block size)'
   360  			show_fees_tooltip(item.pageX, item.pageY, str)
   361  		}
   362  	} else {
   363  		$("#fees_tooltip").remove()
   364  		var x = pos.x
   365  		var y = pos.y
   366  		var show_x = (x >= 0 && x<=totbytes)
   367  		var show_y = (y >= 0 && y<=max_spb)
   368  
   369  		var str = ''
   370  		if (show_y)  str += '<b>' + parseFloat(y).toFixed(2) + '</b> SPB'
   371  		if (show_x) {
   372  			if (str!='')  str += '  |  '
   373  			str += '<b>' + (100.0*x/1e6).toFixed(0) + '%</b>'
   374  		}
   375  		if (str!='') {
   376  			show_cursor_tooltip(pos.pageX, pos.pageY, str)
   377  		}
   378  
   379  		previousPoint = null
   380  	}
   381  }
   382  
   383  function show_fees_clicked(height) {
   384  	var aj = ajax()
   385  	aj.onreadystatechange=function() {
   386  		if(aj.readyState==4) {
   387  			if (prvpos==null) {
   388  				fade.addEventListener('click', closepopup)
   389  				fade.style.cursor = 'pointer'
   390  				fade.title = 'Click here to close the popup'
   391  			}
   392  
   393  			prvpos = document.body.scrollTop
   394  			window.scrollTo(0,0)
   395  
   396  			light.style.display='block'
   397  			fade.style.display='block'
   398  			document.addEventListener("scroll", noscroll)
   399  
   400  
   401  			try {
   402  				var showblfees_stats = JSON.parse(aj.responseText)
   403  
   404  				// hide error message
   405  				stat_error.style.display = 'none'
   406  
   407  				if (block_fees_gru.checked) {
   408  					var stat2 = new Array()
   409  					var curr_elem = [0,0,0]
   410  					for (var i=0; i<showblfees_stats.length; i++) {
   411  						if (showblfees_stats[i][2]!=curr_elem[2]) {
   412  							if (curr_elem[0] > 0) {
   413  								stat2.push(curr_elem)
   414  							}
   415  							curr_elem = [0,0,showblfees_stats[i][2]]
   416  						}
   417  						curr_elem[0] += showblfees_stats[i][0]
   418  						curr_elem[1] += showblfees_stats[i][1]
   419  					}
   420  					if (curr_elem[0] > 0) {
   421  						stat2.push(curr_elem)
   422  					}
   423  					showblfees_stats = stat2
   424  				} else if (block_fees_spb.checked) {
   425  					showblfees_stats.sort(function (a, b) {
   426  						var spb_a = a[1] / a[0]
   427  						var spb_b = b[1] / b[0]
   428  						return ( spb_a < spb_b ) ? 1 : ( (spb_a != spb_b) ? -1 : 0 )
   429  					})
   430  				}
   431  
   432  				fees_plot_data = [ { data : [] } ];
   433  
   434  				var plot_options = {
   435  					xaxis: { position : "top", alignTicksWithAxis: 200 },
   436  					yaxis : { position : "right", tickFormatter : function(a) {return a + " SPB"}, labelWidth : 60 },
   437  					crosshair : {mode: "xy"},
   438  					grid: { hoverable: true, clickable: false },
   439  					points: { show:block_fees_points.checked },
   440  					lines: {show:true, fill:true}
   441  				}
   442  
   443  				var min_spb, spb
   444  				totbytes = 0
   445  				var totfees = 0
   446  				for (var i=0; i<showblfees_stats.length; i++) {
   447  					spb = showblfees_stats[i][1] / (showblfees_stats[i][0] / 4)
   448  					if (i==0) {
   449  						max_spb = min_spb = spb
   450  					} else {
   451  						if (spb>max_spb) max_spb=spb
   452  						else if (spb<min_spb) min_spb=spb
   453  					}
   454  
   455  					totbytes += (showblfees_stats[i][0] / 4)
   456  					totfees += showblfees_stats[i][1]
   457  					fees_plot_data[0].data.push([totbytes, spb])
   458  				}
   459  
   460  				var avg_fee = totfees / totbytes
   461  				stat_max_fee.innerText = max_spb.toFixed(0)
   462  				stat_avg_fee.innerText = avg_fee.toFixed(1)
   463  				stat_min_fee.innerText = min_spb.toFixed(2)
   464  
   465  				if (!block_fees_full.checked) {
   466  					if (block_fees_25.checked) max_spb /= 4
   467  					else  if (block_fees_5.checked) max_spb /= 20
   468  					plot_options.yaxis.max = max_spb
   469  				}
   470  
   471  				$.plot($("#block_fees"), fees_plot_data, plot_options)
   472  
   473  				$("#block_fees").unbind("plothover")
   474  				$("#block_fees").bind("plothover", show_fees_handlehover)
   475  			} catch (e) {
   476  				console.log('error', e)
   477  				error_info.innerText = aj.responseText
   478  				stat_error.style.display = 'block'
   479  				$("#block_fees").empty()
   480  			}
   481  		}
   482  	}
   483  	aj.open("GET","blfees.json?height="+last_height, true);
   484  	aj.send(null);
   485  }
   486  
   487  function show_block_fees(height,size,minedby) {
   488  	last_height = height // for refreshing the chart
   489  	stat_height.innerText = height
   490  	stat_block_size.innerText = size
   491  	stat_mined_by.innerText = minedby
   492  	show_fees_clicked()
   493  }