diff options
Diffstat (limited to 'static/js/calculator.js')
| -rw-r--r-- | static/js/calculator.js | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/static/js/calculator.js b/static/js/calculator.js new file mode 100644 index 00000000..6e71b56a --- /dev/null +++ b/static/js/calculator.js @@ -0,0 +1,310 @@ +(function() { + var ADDRESS_FAIL, API_URL, EXCHANGE_FAIL, SOCKET_FAIL, TEST_URL, clear, fail, fetchExchangeRate, g, getAddress, listen, logTransaction, multiplier, setup, updateTotal; + + EXCHANGE_FAIL = "Problem fetching exchange rate"; + + SOCKET_FAIL = "Problem connecting to payment server, notifications may not appear"; + + ADDRESS_FAIL = "Invalid address"; + + API_URL = "wss://socket.blockcypher.com/v1/btc/main"; + + TEST_URL = "wss://socket.blockcypher.com/v1/btc/test3"; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + g.errors = []; + + g.amount_requested = 0; + + g.amount = 0..toFixed(2); + + g.tip = 1; + + g.transactions = []; + + $(function() { + $.ajax({ + url: $('#user').val() + '.json', + dataType: 'json', + success: function(data) { + g.user = data; + return setup(); + } + }); + $('button').click(function(e) { + return e.preventDefault(); + }); + $('.numpad .btn').off('click').click(function(e) { + var m, n; + e.preventDefault(); + m = $(this).html(); + n = parseFloat($('.amount').html()); + if (m === 'C') { + g.amount = 0..toFixed(2); + updateTotal(); + return; + } + if (n > 10000000) { + return; + } + if (m === '00') { + n = 100 * n; + } else { + n = 10 * n + parseFloat(m) / 100; + } + g.amount = n.toFixed(2); + return updateTotal(); + }); + $('.numpad .btn:last').off('click').click(function(e) { + e.preventDefault(); + g.amount = (Math.floor(100 * (parseFloat($('.amount').html()) / 10)) / 100).toFixed(2); + return updateTotal(); + }); + $('.tippad .btn').off('click').click(function(e) { + var text, value; + e.preventDefault(); + text = $(this).html(); + if (text === 'No Tip') { + value = 0; + } else { + value = text.slice(1, -1); + } + $(this).addClass('active'); + $(this).siblings().removeClass('active'); + g.tip = 1 + (parseFloat(value) / 100); + return updateTotal(); + }); + $('#received').click(function() { + return window.location = "/" + g.user.username + "/report"; + }); + return $('#slide').click(function() { + $('#controls').slideToggle(); + return $(this).find('i').toggleClass('fa-sort-up').toggleClass('fa-sort-down'); + }); + }); + + setup = function() { + var base, base1, base2, base3, base4, ext, src; + (base = g.user).address || (base.address = ''); + (base1 = g.user).commission || (base1.commission = 0); + (base2 = g.user).currency || (base2.currency = 'CAD'); + (base3 = g.user).symbol || (base3.symbol = 'quadrigacx'); + (base4 = g.user).unit || (base4.unit = 'BTC'); + if (g.user.title) { + $('#title').html("<a href='/" + g.user.username + "/edit'>" + g.user.title + "</a>").show(); + } + if (g.user.logo) { + ext = g.user.logo.substr(g.user.logo.length - 3); + src = "/img/logos/" + g.user.username + "." + ext; + $('#logo').attr('src', src).show(); + } + getAddress(); + if (g.user.address[0] === 'm') { + API_URL = TEST_URL; + } + $('.symbol').html(g.user.currency); + $('.currency').html(g.user.currency); + $('.unit').html(g.user.unit); + $('#received').hide(); + fetchExchangeRate(); + return listen(); + }; + + fetchExchangeRate = function() { + $.ajax({ + url: "ticker?currency=" + g.user.currency + "&symbol=" + g.user.symbol + "&type=bid", + success: function(exchange) { + if (exchange != null) { + clear(EXCHANGE_FAIL); + } else { + fail(EXCHANGE_FAIL); + return; + } + g.exchange = (exchange - exchange * g.user.commission * 0.01).toFixed(2); + $('#exchange').html(g.exchange); + updateTotal(); + if (!g.setupComplete) { + return g.setupComplete = true; + } + }, + error: function() { + return fail(EXCHANGE_FAIL); + } + }); + return setTimeout(fetchExchangeRate, 900000); + }; + + updateTotal = function() { + var precision, size, subtotal, time, total; + precision = 9 - multiplier().toString().length; + subtotal = parseFloat(g.amount * g.tip).toFixed(2); + total = (subtotal * multiplier() / g.exchange).toFixed(precision); + g.amount_requested = (subtotal / g.exchange).toFixed(8); + if (!$.isNumeric(total)) { + total = ''; + } + $('#received').hide(); + $('#payment').fadeIn('slow'); + $('.tip').html((subtotal - g.amount).toFixed(2)); + $('.subtotal').html(subtotal.toString()); + $('.amount').html(g.amount); + $('.exchange').html(g.exchange); + $('.symbol').html(g.user.symbol); + if (g.user.commission < 0) { + $('.commission').html("+" + (Math.abs(g.user.commission)) + "%"); + } + $('#total').html(total.toString()); + size = 300; + $('#qr').css('height', size); + time = 0; + if (g.timeout) { + time = 10; + } + clearTimeout(g.timeout); + return g.timeout = setTimeout(function() { + $('#qr').html(''); + return new QRCode('qr', { + text: "bitcoin:" + g.user.address + "?amount=" + (g.amount_requested.toString()), + width: size, + height: size + }); + }, time); + }; + + listen = function() { + g.attempts++; + if (g.blockchain && g.blockchain.readyState === 1) { + return setTimeout(listen, 12000); + } else { + if (g.attempts > 3) { + fail(SOCKET_FAIL); + } + g.blockchain = new WebSocket(API_URL); + g.blockchain.onopen = function() { + if (g.blockchain.readyState === 1) { + g.attempts = 0; + clear(SOCKET_FAIL); + return g.blockchain.send('{"event":"unconfirmed-tx", "address":"' + g.user.address + '"}'); + } else { + return setTimeout(g.blockchain.onopen, 12000 * g.attempts); + } + }; + g.blockchain.onerror = function() { + fail(SOCKET_FAIL); + g.blockchain.close(); + delete g.blockchain; + return listen(); + }; + g.blockchain.onclose = function() { + delete g.blockchain; + return listen(); + }; + return g.blockchain.onmessage = function(e) { + var amount, j, len, output, ref, tx; + tx = JSON.parse(e.data); + amount = 0; + if (tx.hash === g.last_seen) { + return; + } + g.last_seen = tx.hash; + ref = tx.outputs; + for (j = 0, len = ref.length; j < len; j++) { + output = ref[j]; + if (output.addresses[0] === g.user.address) { + amount += output.value / 100000000; + } + } + return logTransaction(tx.hash, amount); + }; + } + }; + + logTransaction = function(txid, amount) { + if ($('#received').is(":hidden") && amount >= g.amount_requested) { + $('#payment').hide(); + $('#received').fadeIn('slow'); + $('#success')[0].play(); + g.user.index++; + if (g.transactions.indexOf(txid) === -1) { + g.transactions.push(txid); + $.post("/" + g.user.username + "/transactions", { + txid: txid, + address: g.user.address, + date: moment().format("YYYY-MM-DD HH:mm:ss"), + received: amount, + exchange: g.exchange, + tip: g.tip + }); + } + return getAddress(); + } + }; + + getAddress = function() { + var child, error, master; + try { + bitcoin.address.fromBase58Check(g.user.pubkey); + g.user.address = g.user.pubkey; + } catch (error) { + master = bitcoin.HDNode.fromBase58(g.user.pubkey); + child = master.derive(0).derive(g.user.index); + g.user.address = child.getAddress().toString(); + if (g.blockchain) { + g.blockchain.close(); + } + listen(); + } + return $('#address').html("<a href='https://blockchain.info/address/" + g.user.address + "'>" + g.user.address + "</a>"); + }; + + fail = function(msg) { + g.errors.push(msg); + g.errors = g.errors.uniq(); + return $('#error').show().html(g.errors.toString()); + }; + + clear = function(msg) { + var i; + i = g.errors.indexOf(msg); + if (i >= 0) { + g.errors.splice(i, 1); + } + if (g.errors.length > 0) { + return $('#error').show().html(g.errors.toString()); + } else { + $('#error').hide(); + return $('#calculator').fadeIn('slow'); + } + }; + + Array.prototype.uniq = function() { + var j, key, output, ref, results, value; + output = {}; + for (key = j = 0, ref = this.length; 0 <= ref ? j < ref : j > ref; key = 0 <= ref ? ++j : --j) { + output[this[key]] = this[key]; + } + results = []; + for (key in output) { + value = output[key]; + results.push(value); + } + return results; + }; + + multiplier = function() { + switch (g.user.unit) { + case 'BTC': + return 1; + case 'mBTC': + return 1000; + case 'µBTC': + return 1000000; + case 'bits': + return 1000000; + case 'satoshis': + return 100000000; + } + }; + +}).call(this); |
