diff --git a/assets/js/tx-sender.js b/assets/js/tx-sender.js index a034945775..f3c418e532 100644 --- a/assets/js/tx-sender.js +++ b/assets/js/tx-sender.js @@ -1,10 +1,31 @@ const set_up_tx_sender = async function() { + ////////////////////////////////////////////////////////////////////////////// + // Notification helpers + ////////////////////////////////////////////////////////////////////////////// + + function successNotif(msg) { + $.bootstrapGrowl(msg, { + delay: 7000, + offset: {from: 'bottom', amount: 68}, + type: 'success', + width: 'auto' + }) + } + function errorNotif(msg) { + $.bootstrapGrowl(msg, { + delay: 7000, + offset: {from: 'bottom', amount: 68}, + type: 'danger', + width: 'auto' + }) + } + ////////////////////////////////////////////////////////////////////////////// // Connection / Setup ////////////////////////////////////////////////////////////////////////////// - FAUCET_URL = "https://faucet.altnet.rippletest.net/accounts" - TESTNET_URL = "wss://s.altnet.rippletest.net:51233" + const FAUCET_URL = "https://faucet.altnet.rippletest.net/accounts" + const TESTNET_URL = "wss://s.altnet.rippletest.net:51233" let connection_ready = false @@ -12,6 +33,7 @@ const set_up_tx_sender = async function() { let sending_secret let xrp_balance + console.debug("Getting a sending address from the faucet...") faucet_response = function(data) { @@ -25,20 +47,15 @@ const set_up_tx_sender = async function() { $(".sending-address-item").text(sending_address) } - // TEMP: reuse same address for testing - faucet_response({account:{address:"r6f2viHtMjNSfERbZmXXkJnMmkBAN6d9X", secret:"spyTc4y4GAQwBfQHCxiJ1Xd2mmnM2"},balance:10000}) - - // POST-TEMP: Version that actually uses the faucet on every run: - // $.ajax({ - // url: FAUCET_URL, - // type: 'POST', - // dataType: 'json', - // success: faucet_response, - // error: function() { - // alert("There was an error with the XRP Ledger Test Net Faucet. Reload this page to try again."); - // } - // }) - // + $.ajax({ + url: FAUCET_URL, + type: 'POST', + dataType: 'json', + success: faucet_response, + error: function() { + errorNotif("There was an error with the XRP Ledger Test Net Faucet. Reload this page to try again.") + } + }) api = new ripple.RippleAPI({server: TESTNET_URL}) api.on('connected', () => { @@ -97,7 +114,9 @@ const set_up_tx_sender = async function() { console.debug("Prepared:", prepared) } catch(error) { console.log(error) - if (!silent) { alert("Error preparing tx: "+error) } + if (!silent) { + errorNotif("Error preparing tx: "+error) + } return } @@ -114,7 +133,9 @@ const set_up_tx_sender = async function() { await api.submit(sign_response.signedTransaction) } catch (error) { console.log(error) - if (!silent) { alert("Error signing & submitting tx: "+error) } + if (!silent) { + errorNotif("Error signing & submitting "+tx_object.TransactionType+" tx: "+error) + } return } @@ -122,18 +143,24 @@ const set_up_tx_sender = async function() { try { const data = await verify_transaction(sign_response.id, options) const final_result = data.outcome.result - // TODO: more "notification-like" system - // TODO: output should link to a tx lookup/explainer + // Future feature: output should link to a TestNet tx lookup/explainer if (final_result === "tesSUCCESS") { - if (!silent) { alert("Tx succeeded (hash:"+sign_response.id+")") } + if (!silent) { + successNotif(tx_object.TransactionType+" tx succeeded (hash: "+sign_response.id+")") + } } else { - if (!silent) { alert("Tx failed w/ code "+final_result+" (hash: "+sign_response.id+")") } + if (!silent) { + errorNotif(tx_object.TransactionType+" tx failed w/ code "+final_result+ + " (hash: "+sign_response.id+")") + } } update_xrp_balance() return data } catch(error) { console.log(error) - if (!silent) { alert("Error submitting tx: "+error) } + if (!silent) { + errorNotif("Error submitting "+tx_object.TransactionType+" tx: "+error) + } } } @@ -284,7 +311,7 @@ const set_up_tx_sender = async function() { Destination: destination_address, Amount: "1000000000000000", // 1 billion XRP SendMax: { - value: String(Math.random()*.01), // random very small amount + value: (Math.random()*.01).toPrecision(15), // random very small amount currency: pp_sending_currency, issuer: pp_issuer_address }, @@ -306,7 +333,7 @@ const set_up_tx_sender = async function() { const duration_seconds = parseInt(duration_seconds_txt, 10) if (duration_seconds === NaN || duration_seconds < 1) { - alert("Error: Escrow duration must be a positive number of seconds") + errorNotif("Error: Escrow duration must be a positive number of seconds") return } const finish_after = api.iso8601ToRippleTime(Date()) + duration_seconds diff --git a/assets/vendor/bootstrap-growl.jquery.js b/assets/vendor/bootstrap-growl.jquery.js new file mode 100644 index 0000000000..9f4289f7f1 --- /dev/null +++ b/assets/vendor/bootstrap-growl.jquery.js @@ -0,0 +1,101 @@ +/* +The MIT License + +Copyright (c) Nick Larson, http://github.com/ifightcrime + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +(function() { + var $; + + $ = jQuery; + + $.bootstrapGrowl = function(message, options) { + var $alert, css, offsetAmount; + options = $.extend({}, $.bootstrapGrowl.default_options, options); + $alert = $("
"); + $alert.attr("class", "bootstrap-growl alert"); + if (options.type) { + $alert.addClass("alert-" + options.type); + } + if (options.allow_dismiss) { + $alert.addClass("alert-dismissible"); + $alert.append(""); + } + $alert.append(message); + if (options.top_offset) { + options.offset = { + from: "top", + amount: options.top_offset + }; + } + offsetAmount = options.offset.amount; + $(".bootstrap-growl").each(function() { + return offsetAmount = Math.max(offsetAmount, parseInt($(this).css(options.offset.from)) + $(this).outerHeight() + options.stackup_spacing); + }); + css = { + "position": (options.ele === "body" ? "fixed" : "absolute"), + "margin": 0, + "z-index": "9999", + "display": "none" + }; + css[options.offset.from] = offsetAmount + "px"; + $alert.css(css); + if (options.width !== "auto") { + $alert.css("width", options.width + "px"); + } + $(options.ele).append($alert); + switch (options.align) { + case "center": + $alert.css({ + "left": "50%", + "margin-left": "-" + ($alert.outerWidth() / 2) + "px" + }); + break; + case "left": + $alert.css("left", "20px"); + break; + default: + $alert.css("right", "20px"); + } + $alert.fadeIn(); + if (options.delay > 0) { + $alert.delay(options.delay).fadeOut(function() { + return $(this).alert("close"); + }); + } + return $alert; + }; + + $.bootstrapGrowl.default_options = { + ele: "body", + type: "info", + offset: { + from: "top", + amount: 20 + }, + align: "right", + width: 250, + delay: 4000, + allow_dismiss: true, + stackup_spacing: 10 + }; + +}).call(this); diff --git a/tool/template-tx-sender.html b/tool/template-tx-sender.html index 8a082b12bf..586d206ee5 100644 --- a/tool/template-tx-sender.html +++ b/tool/template-tx-sender.html @@ -150,5 +150,6 @@ {% block endbody %} - + + {% endblock %}