github.com/jackcoble/blockbook@v0.3.2/static/test-websocket.html (about) 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 6 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> 7 <style> 8 .row { 9 margin-top: 1%; 10 } 11 </style> 12 <title>Blockbook Websocket Test Page</title> 13 <script> 14 var ws; 15 var messageID; 16 var pendingMessages; 17 var subscriptions; 18 function send(method, params, callback) { 19 var id = messageID.toString(); 20 messageID++; 21 pendingMessages[id] = callback; 22 var req = { 23 id, 24 method, 25 params 26 } 27 ws.send(JSON.stringify(req)); 28 return id; 29 } 30 function subscribe(method, params, callback) { 31 var id = messageID.toString(); 32 messageID++; 33 subscriptions[id] = callback; 34 var req = { 35 id, 36 method, 37 params 38 } 39 ws.send(JSON.stringify(req)); 40 return id; 41 } 42 function unsubscribe(method, id, params, callback) { 43 delete subscriptions[id]; 44 pendingMessages[id] = callback; 45 var req = { 46 id, 47 method, 48 params 49 } 50 ws.send(JSON.stringify(req)); 51 return id; 52 } 53 function connect(server) { 54 messageID = 0; 55 pendingMessages = {}; 56 subscriptions = {}; 57 subscribeNewBlockId = ""; 58 subscribeAddressesId = ""; 59 if (server.startsWith("http")) { 60 server = server.replace("http", "ws"); 61 } 62 if (!server.endsWith("/websocket")) { 63 server += "/websocket"; 64 } 65 ws = new WebSocket(server); 66 ws.onopen = function (e) { 67 console.log('socket connected', e); 68 document.getElementById('connectionStatus').innerText = "connected"; 69 }; 70 ws.onclose = function (e) { 71 console.log('socket closed', e); 72 document.getElementById('connectionStatus').innerText = "disconnected"; 73 }; 74 ws.onerror = function (e) { 75 console.log('socket error ', e); 76 document.getElementById('connectionStatus').innerText = "error"; 77 }; 78 ws.onmessage = function (e) { 79 console.log('resp ' + e.data); 80 var resp = JSON.parse(e.data); 81 var f = pendingMessages[resp.id]; 82 if (f != undefined) { 83 delete pendingMessages[resp.id]; 84 f(resp.data); 85 } else { 86 f = subscriptions[resp.id]; 87 if (f != undefined) { 88 f(resp.data); 89 } 90 else { 91 console.log("unkown response " + resp.id); 92 } 93 } 94 }; 95 } 96 97 function getInfo() { 98 const method = 'getInfo'; 99 const params = { 100 }; 101 send(method, params, function (result) { 102 document.getElementById('getInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 103 }); 104 } 105 106 function ping() { 107 const method = 'ping'; 108 const params = { 109 }; 110 send(method, params, function (result) { 111 document.getElementById('pingResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 112 }); 113 } 114 115 function getBlockHash() { 116 const method = 'getBlockHash'; 117 const height = parseInt(document.getElementById("getBlockHashHeight").value); 118 const params = { 119 height 120 }; 121 send(method, params, function (result) { 122 document.getElementById('getBlockHashResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 123 }); 124 } 125 126 function getAccountInfo() { 127 const descriptor = document.getElementById('getAccountInfoDescriptor').value.trim(); 128 const selectDetails = document.getElementById('getAccountInfoDetails'); 129 const details = selectDetails.options[selectDetails.selectedIndex].value; 130 const page = parseInt(document.getElementById("getAccountInfoPage").value); 131 const from = parseInt(document.getElementById("getAccountInfoFrom").value); 132 const to = parseInt(document.getElementById("getAccountInfoTo").value); 133 const contractFilter = document.getElementById("getAccountInfoContract").value.trim(); 134 const pageSize = 10; 135 const method = 'getAccountInfo'; 136 const tokens = "derived"; // could be "nonzero", "used", default is "derived" i.e. all 137 const params = { 138 descriptor, 139 details, 140 tokens, 141 page, 142 pageSize, 143 from, 144 to, 145 contractFilter 146 // default gap=20 147 }; 148 send(method, params, function (result) { 149 document.getElementById('getAccountInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 150 }); 151 } 152 153 function getAccountUtxo() { 154 const descriptor = document.getElementById('getAccountUtxoDescriptor').value.trim(); 155 const method = 'getAccountUtxo'; 156 const params = { 157 descriptor, 158 }; 159 send(method, params, function (result) { 160 document.getElementById('getAccountUtxoResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 161 }); 162 } 163 164 function getBalanceHistory() { 165 const descriptor = document.getElementById('getBalanceHistoryDescriptor').value.trim(); 166 const from = parseInt(document.getElementById("getBalanceHistoryFrom").value.trim()); 167 const to = parseInt(document.getElementById("getBalanceHistoryTo").value.trim()); 168 const currencies = document.getElementById('getBalanceHistoryFiat').value.split(","); 169 const groupBy = parseInt(document.getElementById("getBalanceHistoryGroupBy").value); 170 const method = 'getBalanceHistory'; 171 const params = { 172 descriptor, 173 from, 174 to, 175 currencies, 176 groupBy 177 // default gap=20 178 }; 179 send(method, params, function (result) { 180 document.getElementById('getBalanceHistoryResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 181 }); 182 } 183 184 185 function getTransaction() { 186 const txid = document.getElementById('getTransactionTxid').value.trim(); 187 const method = 'getTransaction'; 188 const params = { 189 txid, 190 }; 191 send(method, params, function (result) { 192 document.getElementById('getTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 193 }); 194 } 195 196 function getTransactionSpecific() { 197 const txid = document.getElementById('getTransactionSpecificTxid').value.trim(); 198 const method = 'getTransactionSpecific'; 199 const params = { 200 txid, 201 }; 202 send(method, params, function (result) { 203 document.getElementById('getTransactionSpecificResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 204 }); 205 } 206 207 function estimateFee() { 208 try { 209 var blocks = document.getElementById('estimateFeeBlocks').value.split(","); 210 var specific = document.getElementById('estimateFeeSpecific').value.trim(); 211 if (specific) { 212 // example for bitcoin type: {"conservative": false,"txsize":1234} 213 // example for ethereum type: {"from":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","to":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","data":"0xabcd"} 214 specific = JSON.parse(specific) 215 } 216 else { 217 specific = undefined; 218 } 219 blocks = blocks.map(s => parseInt(s.trim())); 220 const method = 'estimateFee'; 221 const params = { 222 blocks, 223 specific 224 }; 225 send(method, params, function (result) { 226 document.getElementById('estimateFeeResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 227 }); 228 } 229 catch (e) { 230 document.getElementById('estimateFeeResult').innerText = e; 231 } 232 } 233 234 function sendTransaction() { 235 var hex = document.getElementById('sendTransactionHex').value.trim(); 236 const method = 'sendTransaction'; 237 const params = { 238 hex, 239 }; 240 send(method, params, function (result) { 241 document.getElementById('sendTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 242 }); 243 } 244 245 function subscribeNewBlock() { 246 const method = 'subscribeNewBlock'; 247 const params = { 248 }; 249 if (subscribeNewBlockId) { 250 delete subscriptions[subscribeNewBlockId]; 251 subscribeNewBlockId = ""; 252 } 253 subscribeNewBlockId = subscribe(method, params, function (result) { 254 document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 255 }); 256 document.getElementById('subscribeNewBlockId').innerText = subscribeNewBlockId; 257 document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: inherit;"); 258 } 259 260 function unsubscribeNewBlock() { 261 const method = 'unsubscribeNewBlock'; 262 const params = { 263 }; 264 unsubscribe(method, subscribeNewBlockId, params, function (result) { 265 subscribeNewBlockId = ""; 266 document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 267 document.getElementById('subscribeNewBlockId').innerText = ""; 268 document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: none;"); 269 }); 270 } 271 272 function subscribeAddresses() { 273 const method = 'subscribeAddresses'; 274 var addresses = document.getElementById('subscribeAddressesName').value.split(","); 275 addresses = addresses.map(s => s.trim()); 276 const params = { 277 addresses 278 }; 279 if (subscribeAddressesId) { 280 delete subscriptions[subscribeAddressesId]; 281 subscribeAddressesId = ""; 282 } 283 subscribeAddressesId = subscribe(method, params, function (result) { 284 document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 285 }); 286 document.getElementById('subscribeAddressesIds').innerText = subscribeAddressesId; 287 document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: inherit;"); 288 } 289 290 function unsubscribeAddresses() { 291 const method = 'unsubscribeAddresses'; 292 const params = { 293 }; 294 unsubscribe(method, subscribeAddressesId, params, function (result) { 295 subscribeAddressesId = ""; 296 document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 297 document.getElementById('subscribeAddressesIds').innerText = ""; 298 document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: none;"); 299 }); 300 } 301 302 function getFiatRatesForTimestamps() { 303 const method = 'getFiatRatesForTimestamps'; 304 var timestamps = document.getElementById('getFiatRatesForTimestampsList').value.split(","); 305 var currencies = document.getElementById('getFiatRatesForTimestampsCurrency').value.split(","); 306 timestamps = timestamps.map(Number); 307 const params = { 308 timestamps, 309 'currencies': currencies 310 }; 311 send(method, params, function (result) { 312 document.getElementById('getFiatRatesForTimestampsResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 313 }); 314 } 315 316 function getCurrentFiatRates() { 317 const method = 'getCurrentFiatRates'; 318 var currencies = document.getElementById('getCurrentFiatRatesCurrency').value.split(","); 319 const params = { 320 "currencies": currencies 321 }; 322 send(method, params, function (result) { 323 document.getElementById('getCurrentFiatRatesResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 324 }); 325 } 326 327 function getFiatRatesTickersList() { 328 const method = 'getFiatRatesTickersList'; 329 var timestamp = document.getElementById('getFiatRatesTickersListDate').value; 330 timestamp = parseInt(timestamp); 331 const params = { 332 timestamp, 333 }; 334 send(method, params, function (result) { 335 document.getElementById('getFiatRatesTickersListResult').innerText = JSON.stringify(result).replace(/,/g, ", "); 336 }); 337 } 338 339 function subscribeNewFiatRatesTicker() { 340 const method = 'subscribeFiatRates'; 341 var currency = document.getElementById('subscribeFiatRatesCurrency').value; 342 const params = { 343 "currency": currency 344 }; 345 if (subscribeNewFiatRatesTickerId) { 346 delete subscriptions[subscribeNewFiatRatesTickerId]; 347 subscribeNewFiatRatesTickerId = ""; 348 } 349 subscribeNewFiatRatesTickerId = subscribe(method, params, function (result) { 350 document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 351 }); 352 document.getElementById('subscribeNewFiatRatesTickerId').innerText = subscribeNewFiatRatesTickerId; 353 document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: inherit;"); 354 } 355 356 function unsubscribeNewFiatRatesTicker() { 357 const method = 'unsubscribeFiatRates'; 358 const params = { 359 }; 360 unsubscribe(method, subscribeNewFiatRatesTickerId, params, function (result) { 361 subscribeNewFiatRatesTickerId = ""; 362 document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n"; 363 document.getElementById('subscribeNewFiatRatesTickerId').innerText = ""; 364 document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: none;"); 365 }); 366 } 367 </script> 368 </head> 369 370 <body> 371 <div class="container"> 372 <div class="row justify-content-center"> 373 <h1>Blockbook Websocket Test Page</h1> 374 </div> 375 <div class="row"> 376 <div class="col"> 377 <input class="btn btn-secondary" type="button" value="Login" onclick="connect(document.getElementById('serverAddress').value)"> 378 </div> 379 <div class="col-8"> 380 <input type="text" class="form-control" id="serverAddress" value=""> 381 </div> 382 <div class="col form-inline"> 383 <label id="connectionStatus">not connected</label> 384 </div> 385 </div> 386 <div class="row"> 387 <div class="col"> 388 <input class="btn btn-secondary" type="button" value="getInfo" onclick="getInfo()"> 389 </div> 390 <div class="col-10" id="getInfoResult"> 391 </div> 392 </div> 393 <div class="row"> 394 <div class="col"> 395 <input class="btn btn-secondary" type="button" value="ping" onclick="ping()"> 396 </div> 397 <div class="col-10" id="pingResult"> 398 </div> 399 </div> 400 <div class="row"> 401 <div class="col"> 402 <input class="btn btn-secondary" type="button" value="getBlockHash" onclick="getBlockHash()"> 403 </div> 404 <div class="col-8"> 405 <input type="text" class="form-control" placeholder="height" id="getBlockHashHeight" value="0"> 406 </div> 407 <div class="col"> 408 </div> 409 </div> 410 <div class="row"> 411 <div class="col" id="getBlockHashResult"></div> 412 </div> 413 <div class="row"> 414 <div class="col"> 415 <input class="btn btn-secondary" type="button" value="getAccountInfo" onclick="getAccountInfo()"> 416 </div> 417 <div class="col-8"> 418 <div class="row" style="margin: 0;"> 419 <input type="text" placeholder="descriptor" style="width: 79%" class="form-control" id="getAccountInfoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd"> 420 <select id="getAccountInfoDetails" style="width: 20%; margin-left: 5px;"> 421 <option value="basic">Basic</option> 422 <option value="tokens">Tokens</option> 423 <option value="tokenBalances">TokenBalances</option> 424 <option value="txids">Txids</option> 425 <option value="txs">Transactions</option> 426 </select> 427 </div> 428 <div class="row" style="margin: 0; margin-top: 5px;"> 429 <input type="text" placeholder="page" style="width: 10%; margin-right: 5px;" class="form-control" id="getAccountInfoPage"> 430 <input type="text" placeholder="from" style="width: 15%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getAccountInfoFrom"> 431 <input type="text" placeholder="to" style="width: 15%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoTo"> 432 <input type="text" placeholder="contract" style="width: 55%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoContract"> 433 </div> 434 </div> 435 <div class="col form-inline"></div> 436 </div> 437 <div class="row"> 438 <div class="col" id="getAccountInfoResult"> 439 </div> 440 </div> 441 <div class="row"> 442 <div class="col"> 443 <input class="btn btn-secondary" type="button" value="getAccountUtxo" onclick="getAccountUtxo()"> 444 </div> 445 <div class="col-8"> 446 <div class="row" style="margin: 0;"> 447 <input type="text" placeholder="descriptor" class="form-control" id="getAccountUtxoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd"> 448 </div> 449 </div> 450 <div class="col form-inline"></div> 451 </div> 452 <div class="row"> 453 <div class="col" id="getAccountUtxoResult"> 454 </div> 455 </div> 456 <div class="row"> 457 <div class="col"> 458 <input class="btn btn-secondary" type="button" value="getBalanceHistory" onclick="getBalanceHistory()"> 459 </div> 460 <div class="col-8"> 461 <div class="row" style="margin: 0;"> 462 <input type="text" placeholder="descriptor" class="form-control" id="getBalanceHistoryDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd"> 463 </div> 464 <div class="row" style="margin: 0; margin-top: 5px;"> 465 <input type="text" placeholder="from Unix TS" style="width: 20%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getBalanceHistoryFrom"> 466 <input type="text" placeholder="to Unix TS" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryTo"> 467 <input type="text" placeholder="usd,eur" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryFiat"> 468 <input type="text" placeholder="group by (sec)" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryGroupBy"> 469 </div> 470 </div> 471 <div class="col form-inline"></div> 472 </div> 473 <div class="row"> 474 <div class="col" id="getBalanceHistoryResult"> 475 </div> 476 </div> 477 <div class="row"> 478 <div class="col"> 479 <input class="btn btn-secondary" type="button" value="getTransaction" onclick="getTransaction()"> 480 </div> 481 <div class="col-8"> 482 <div class="row" style="margin: 0;"> 483 <input type="text" placeholder="txid" class="form-control" id="getTransactionTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574"> 484 </div> 485 </div> 486 <div class="col form-inline"></div> 487 </div> 488 <div class="row"> 489 <div class="col" id="getTransactionResult"> 490 </div> 491 </div> 492 <div class="row"> 493 <div class="col"> 494 <input class="btn btn-secondary" type="button" value="getTransactionSpecific" onclick="getTransactionSpecific()"> 495 </div> 496 <div class="col-8"> 497 <div class="row" style="margin: 0;"> 498 <input type="text" placeholder="txid" class="form-control" id="getTransactionSpecificTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574"> 499 </div> 500 </div> 501 <div class="col form-inline"></div> 502 </div> 503 <div class="row"> 504 <div class="col" id="getTransactionSpecificResult"> 505 </div> 506 </div> 507 <div class="row"> 508 <div class="col"> 509 <input class="btn btn-secondary" type="button" value="estimateFee" onclick="estimateFee()"> 510 </div> 511 <div class="col-8"> 512 <div class="row" style="margin: 0;"> 513 <input type="text" placeholder="comma separated list of block targets" class="form-control" id="estimateFeeBlocks" value="2,5,10,20"> 514 </div> 515 <div class="row" style="margin: 0; margin-top: 5px;"> 516 <input type="text" placeholder="tx specific JSON" class="form-control" id="estimateFeeSpecific" value=""> 517 </div> 518 </div> 519 <div class="col"></div> 520 </div> 521 <div class="row"> 522 <div class="col" id="estimateFeeResult"> 523 </div> 524 </div> 525 <div class="row"> 526 <div class="col"> 527 <input class="btn btn-secondary" type="button" value="sendTransaction" onclick="sendTransaction()"> 528 </div> 529 <div class="col-8"> 530 <input type="text" class="form-control" id="sendTransactionHex" value="010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"> 531 </div> 532 <div class="col"> 533 </div> 534 </div> 535 <div class="row"> 536 <div class="col" id="sendTransactionResult"></div> 537 </div> 538 <div class="row"> 539 <div class="col-2"> 540 <input class="btn btn-secondary" type="button" value="get fiat rates for dates" onclick="getFiatRatesForTimestamps()"> 541 </div> 542 <div class="col-1"> 543 <input type="text" class="form-control" id="getFiatRatesForTimestampsCurrency" placeholder="usd,eur"> 544 </div> 545 <div class="col-7"> 546 <input type="text" class="form-control" id="getFiatRatesForTimestampsList" value="1575288000,1575550800"> 547 </div> 548 </div> 549 <div class="row"> 550 <div class="col" id="getFiatRatesForTimestampsResult"></div> 551 </div> 552 <div class="row"> 553 <div class="col-2"> 554 <input class="btn btn-secondary" type="button" value="get current fiat rates" onclick="getCurrentFiatRates()"> 555 </div> 556 <div class="col-1"> 557 <input type="text" class="form-control" id="getCurrentFiatRatesCurrency" placeholder="usd"> 558 </div> 559 </div> 560 <div class="row"> 561 <div class="col" id="getCurrentFiatRatesResult"></div> 562 </div> 563 <div class="row"> 564 <div class="col-2"> 565 <input class="btn btn-secondary" type="button" value="get fiat rates tickers" onclick="getFiatRatesTickersList()"> 566 </div> 567 <div class="col-8"> 568 <input type="text" class="form-control" id="getFiatRatesTickersListDate" value="1576591569" placeholder="Unix timestamp"> 569 </div> 570 </div> 571 <div class="row"> 572 <div class="col" id="getFiatRatesTickersListResult"></div> 573 </div> 574 <div class="row"> 575 <div class="col"> 576 <input class="btn btn-secondary" type="button" value="subscribe new block" onclick="subscribeNewBlock()"> 577 </div> 578 <div class="col-4"> 579 <span id="subscribeNewBlockId"></span> 580 </div> 581 <div class="col"> 582 <input class="btn btn-secondary" id="unsubscribeNewBlockButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewBlock()"> 583 </div> 584 </div> 585 <div class="row"> 586 <div class="col" id="subscribeNewBlockResult"></div> 587 </div> 588 <div class="row"> 589 <div class="col"> 590 <input class="btn btn-secondary" type="button" value="subscribe address" onclick="subscribeAddresses()"> 591 </div> 592 <div class="col-8"> 593 <input type="text" class="form-control" id="subscribeAddressesName" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd,0x73d0385f4d8e00c5e6504c6030f47bf6212736a8"> 594 </div> 595 <div class="col"> 596 <span id="subscribeAddressesIds"></span> 597 </div> 598 <div class="col"> 599 <input class="btn btn-secondary" id="unsubscribeAddressesButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeAddresses()"> 600 </div> 601 </div> 602 <div class="row"> 603 <div class="col" id="subscribeAddressesResult"></div> 604 </div> 605 <div class="row"> 606 <div class="col-3"> 607 <input class="btn btn-secondary" type="button" value="subscribe new fiat rates" onclick="subscribeNewFiatRatesTicker()"> 608 </div> 609 <div class="col-1"> 610 <span id="subscribeNewFiatRatesTickerId"></span> 611 </div> 612 <div class="col-1"> 613 <input type="text" class="form-control" id="subscribeFiatRatesCurrency" value="usd"> 614 </div> 615 <div class="col-5"> 616 <input class="btn btn-secondary" id="unsubscribeNewFiatRatesTickerButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewFiatRatesTicker()"> 617 </div> 618 </div> 619 <div class="row"> 620 <div class="col" id="subscribeNewFiatRatesTickerResult"></div> 621 </div> 622 </div> 623 <br><br> 624 </body> 625 <script> 626 document.getElementById('serverAddress').value = window.location.protocol + "//" + window.location.host; 627 </script> 628 629 </html>