From 5255f026a68be987dbccc191900752d7e9daf1af Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 15 Jul 2014 00:44:25 -0700 Subject: Add menu, change view engine, use Grunt --- public/js/calculator.coffee | 2 +- public/js/calculator.js | 231 ++++++++++++++++++++++++++++++++++++++++++++ public/js/deposit.js | 102 +++++++++++++++++++ public/js/index.js | 51 ++++++++++ public/js/register.js | 6 ++ public/js/report.js | 63 ++++++++++++ public/js/setup.coffee | 5 +- public/js/setup.js | 72 ++++++++++++++ 8 files changed, 530 insertions(+), 2 deletions(-) create mode 100644 public/js/calculator.js create mode 100644 public/js/deposit.js create mode 100644 public/js/index.js create mode 100644 public/js/register.js create mode 100644 public/js/report.js create mode 100644 public/js/setup.js (limited to 'public/js') diff --git a/public/js/calculator.coffee b/public/js/calculator.coffee index 99560e86..039ffd73 100644 --- a/public/js/calculator.coffee +++ b/public/js/calculator.coffee @@ -80,7 +80,7 @@ setup = -> $('#logo').click -> $(location).attr("href","/#{g.user}/edit") address = g.address if g.user? and g.user - address = "#{address}" + address = "#{address}" if check_address(g.address) $('#address').html(address) diff --git a/public/js/calculator.js b/public/js/calculator.js new file mode 100644 index 00000000..88fcbd22 --- /dev/null +++ b/public/js/calculator.js @@ -0,0 +1,231 @@ +(function() { + var ADDRESS_FAIL, EXCHANGE_FAIL, SOCKET_FAIL, activateTip, clear, fail, fetchExchangeRate, finalize, g, get, setup, setupSocket, tip, updateTotal; + + EXCHANGE_FAIL = "Error fetching exchange rate"; + + SOCKET_FAIL = "Error connecting to payment server"; + + ADDRESS_FAIL = "Invalid address"; + + tip = 1; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + $(function() { + g.user = $('#user').val(); + g.title = get('title'); + g.address = get('address'); + g.symbol = get('symbol'); + g.currency = get('currency'); + g.commission = parseFloat(get('commission')); + g.logo = get('logo'); + g.errors = []; + g.receivable = 0; + if (g.user) { + $.ajax({ + url: g.user + '.json', + dataType: 'json', + success: function(data) { + if (data != null) { + g.title = data.title; + g.address = data.address; + g.currency = data.currency; + g.symbol = data.symbol; + g.commission = data.commission; + g.logo = data.logo; + } + return setup(); + } + }); + } else { + setup(); + } + $('#tip button').click(function() { + var value; + value = $(this).html().slice(0, -1); + $(this).siblings().css('font-weight', 'normal').removeClass('active'); + $(this).css('font-weight', 'bold'); + tip = 1 + (parseFloat(value) / 100); + return updateTotal(); + }); + $('#tip button').first().click(); + $('#amount').keyup(updateTotal); + return $('#amount').focus(function() { + $('#received').hide(); + $('#payment').fadeIn('slow'); + $(this).val(''); + return updateTotal(); + }); + }); + + activateTip = function(p) {}; + + setup = function() { + var address; + g.address || (g.address = ''); + g.commission || (g.commission = 0); + g.symbol || (g.symbol = 'quadrigacx'); + if (g.title) { + $('#title').html(g.title).show(); + } + if (g.logo) { + $('#logo').attr('src', g.logo).show(); + } else if (!g.title) { + $('#logo').attr('src', 'img/bitcoin.png').show(); + } + $('#logo').click(function() { + return $(location).attr("href", "/" + g.user + "/edit"); + }); + address = g.address; + if ((g.user != null) && g.user) { + address = "" + address + ""; + } + if (check_address(g.address)) { + $('#address').html(address); + } else { + fail(ADDRESS_FAIL); + } + $('#symbol').html(g.symbol + " bid"); + $('#currency').html(g.currency); + $('#received').hide(); + return fetchExchangeRate(); + }; + + fetchExchangeRate = function() { + $.ajax({ + url: "ticker?currency=" + g.currency + "&symbol=" + g.symbol + "&type=bid", + success: function(exchange) { + if (exchange != null) { + clear(EXCHANGE_FAIL); + } else { + fail(EXCHANGE_FAIL); + return; + } + if (!g.setupComplete) { + finalize(); + } + g.exchange = exchange - exchange * g.commission * 0.01; + $('#exchange').val(g.exchange.toFixed(2)); + return updateTotal(); + }, + error: function() { + return fail(EXCHANGE_FAIL); + } + }); + return setTimeout(fetchExchangeRate, 900000); + }; + + finalize = function() { + $('#amount').focus(); + return g.setupComplete = true; + }; + + setupSocket = function() { + setTimeout(setupSocket, 10000); + if (!(g.websocket && g.websocket.readyState === 1)) { + g.websocket = new WebSocket("wss://ws.blockchain.info/inv"); + g.websocket.onopen = function() { + return g.websocket.send('{"op":"addr_sub", "addr":"' + g.address + '"}'); + }; + g.websocket.onerror = function() { + g.websocket = null; + return fail(SOCKET_FAIL); + }; + g.websocket.onclose = function() { + return setupSocket(); + }; + return g.websocket.onmessage = function(e) { + var from_address, received, results; + results = eval('(' + e.data + ')'); + from_address = ''; + received = 0; + $.each(results.x.out, function(i, v) { + if (v.addr === g.address) { + return received += v.value / 100000000; + } + }); + $.each(results.x.inputs, function(i, v) { + from_address = v.prev_out.addr; + if (v.prev_out.addr === g.address) { + return input -= v.prev_out.value / 100000000; + } + }); + if (g.receivable <= received) { + $('#amount').blur(); + $('#payment').hide(); + $('#received').fadeIn('slow'); + } + if (g.user) { + return $.post("/" + g.user + "/transactions", { + address: from_address, + date: moment().format("YYYY-MM-DD HH:mm:ss"), + received: received, + exchange: g.exchange + }); + } + }; + } + }; + + updateTotal = function() { + var amount, total; + amount = parseFloat($('#amount').val() * tip); + total = (amount * 1000 / g.exchange).toFixed(5); + g.receivable = (amount / g.exchange).toFixed(8); + if (!$.isNumeric(total)) { + total = ''; + } + $('#total').html(total.toString()); + $('#qr').html(''); + return new QRCode('qr', "bitcoin:" + g.address + "?amount=" + (g.receivable.toString())); + }; + + fail = function(msg) { + g.errors.push(msg); + g.errors = g.errors.uniq(); + $('#calculator').hide(); + 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'); + } + }; + + get = function(name) { + var regex, regexS, results; + name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + regexS = "[\\?&]" + name + "=([^&#]*)"; + regex = new RegExp(regexS); + results = regex.exec(window.location.search); + if (results === null) { + return ""; + } else { + return decodeURIComponent(results[1].replace(/\+/g, " ")); + } + }; + + Array.prototype.uniq = function() { + var key, output, value, _i, _ref, _results; + output = {}; + for (key = _i = 0, _ref = this.length; 0 <= _ref ? _i < _ref : _i > _ref; key = 0 <= _ref ? ++_i : --_i) { + output[this[key]] = this[key]; + } + _results = []; + for (key in output) { + value = output[key]; + _results.push(value); + } + return _results; + }; + +}).call(this); diff --git a/public/js/deposit.js b/public/js/deposit.js new file mode 100644 index 00000000..3bb5bf23 --- /dev/null +++ b/public/js/deposit.js @@ -0,0 +1,102 @@ +(function() { + var ADDRESS_FAIL, EXCHANGE_FAIL, SOCKET_FAIL, clear, fail, g, get, setupSocket; + + EXCHANGE_FAIL = "Error fetching exchange rate"; + + SOCKET_FAIL = "Error connecting to payment server"; + + ADDRESS_FAIL = "Invalid address"; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + $(function() { + g.address || (g.address = '1VAnbtCAnYccECnjaMCPnWwt81EHCVgNr'); + setupSocket(); + setupQR(); + return displayQR('bitcoin:' + g.address); + }); + + setupSocket = function() { + g.address = "1VAnbtCAnYccECnjaMCPnWwt81EHCVgNr"; + setTimeout(setupSocket, 10000); + if (!(g.websocket && g.websocket.readyState === 1)) { + g.websocket = new WebSocket("ws://api.blockchain.info:8335/inv"); + g.websocket.onopen = function() { + return g.websocket.send('{"op":"addr_sub", "addr":"' + g.address + '"}'); + }; + g.websocket.onerror = g.websocket.onclose = function() { + return fail(SOCKET_FAIL); + }; + return g.websocket.onmessage = function(e) { + var from_address, received, results, total; + results = eval('(' + e.data + ')'); + from_address = ''; + total = 0; + received = 0; + $.each(results.x.out, function(i, v) { + if (v.addr === g.address) { + return received += v.value; + } + }); + $.each(results.x.inputs, function(i, v) { + from_address = v.prev_out.addr; + if (v.prev_out.addr === g.address) { + return input -= v.prev_out.value; + } + }); + return $.get("/issue/" + received, function(data) { + return $('#received').text(data); + }); + }; + } + }; + + fail = function(msg) { + g.errors.push(msg); + g.errors = g.errors.uniq(); + $('#calculator').hide(); + 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'); + } + }; + + get = function(name) { + var regex, regexS, results; + name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + regexS = "[\\?&]" + name + "=([^&#]*)"; + regex = new RegExp(regexS); + results = regex.exec(window.location.search); + if (results === null) { + return ""; + } else { + return decodeURIComponent(results[1].replace(/\+/g, " ")); + } + }; + + Array.prototype.uniq = function() { + var key, output, value, _i, _ref, _results; + output = {}; + for (key = _i = 0, _ref = this.length; 0 <= _ref ? _i < _ref : _i > _ref; key = 0 <= _ref ? ++_i : --_i) { + output[this[key]] = this[key]; + } + _results = []; + for (key in output) { + value = output[key]; + _results.push(value); + } + return _results; + }; + +}).call(this); diff --git a/public/js/index.js b/public/js/index.js new file mode 100644 index 00000000..7b799c1e --- /dev/null +++ b/public/js/index.js @@ -0,0 +1,51 @@ +(function() { + var fetchExchangeRate, g; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + $(function() { + fetchExchangeRate('ask'); + fetchExchangeRate('bid'); + $('#username').blur(function() { + return $.get("/" + ($(this).val()) + "/exists", { + username: $(this).val() + }, function(data) { + if (data === "true") { + $('#username').prev().css('color', 'red').html('Username (taken)'); + return g.preventSubmit = true; + } else { + $('#username').prev().css('color', 'black').html('Username'); + return g.preventSubmit = false; + } + }); + }); + return $('#signup').submit(function() { + if (g.preventSubmit) { + return false; + } + return true; + }); + }); + + fetchExchangeRate = function(type) { + var commission; + commission = 0.015; + if (type === 'bid') { + commission *= -1; + } + return $.ajax({ + url: "/ticker?symbol=virtexCAD&type=" + type + "&amount=100", + success: function(exchange) { + if (exchange == null) { + exchange = '??'; + } + exchange = exchange - exchange * commission; + return $("#" + type).html(exchange.toFixed(2)); + }, + error: function() { + return $("#" + type).html('??'); + } + }); + }; + +}).call(this); diff --git a/public/js/register.js b/public/js/register.js new file mode 100644 index 00000000..b75cc305 --- /dev/null +++ b/public/js/register.js @@ -0,0 +1,6 @@ +(function() { + $(function() { + return $('#username').focus(); + }); + +}).call(this); diff --git a/public/js/report.js b/public/js/report.js new file mode 100644 index 00000000..1fd882a7 --- /dev/null +++ b/public/js/report.js @@ -0,0 +1,63 @@ +(function() { + var display, filterDates, g; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + $(function() { + $('#from').val(moment().subtract('days', 7).format("MM/DD/YYYY")); + $('#to').val(moment().format("MM/DD/YYYY")); + $('.date').datepicker({ + onClose: filterDates + }); + return $.getJSON('transactions.json', function(data) { + g.transactions = data.transactions; + display(g.transactions); + return filterDates(); + }); + }); + + filterDates = function() { + var transactions; + transactions = $.grep(g.transactions, function(e, i) { + var amount, d, from, to; + if (!e) { + return false; + } + from = moment($('#from').val(), "MM/DD/YYYY"); + to = moment($('#to').val(), "MM/DD/YYYY"); + d = moment(e.date); + amount = parseFloat(e.exchange) * parseFloat(e.received); + return !isNaN(parseFloat(amount)) && isFinite(amount) && ((from == null) || d.diff(from) >= 0) && ((to == null) || d.diff(to) <= 0); + }); + return display(transactions); + }; + + display = function(transactions) { + var btc, cad; + $('tbody tr').remove(); + $('thead, tfoot').show(); + if (transactions.length === 0) { + $('tbody').append("\n \n No transactions were found for the specified time period\n \n"); + $('thead, tfoot').hide(); + } + $.each(transactions, function() { + var amount, exchange, received; + exchange = parseFloat(this.exchange); + received = parseFloat(this.received); + amount = received * exchange; + received *= 1000; + return $('tbody').append("\n " + this.date + "\n " + this.address + "\n " + (exchange.toFixed(2)) + "\n " + (received.toFixed(5)) + "\n " + (amount.toFixed(2)) + "\n"); + }); + btc = 0; + $('table.report td:nth-child(4)').each(function() { + return btc += parseFloat($(this).html()); + }); + $('#btc').html(btc.toFixed(5)); + cad = 0; + $('table.report td:nth-child(5)').each(function() { + return cad += parseFloat($(this).html()); + }); + return $('#cad').html(cad.toFixed(2)); + }; + +}).call(this); diff --git a/public/js/setup.coffee b/public/js/setup.coffee index e8b4e09b..9b4bf5d2 100644 --- a/public/js/setup.coffee +++ b/public/js/setup.coffee @@ -8,6 +8,7 @@ g = exports ? this g.proceed = false $(-> + $('#title').focus() $.getJSON("/js/rates.json", (data) -> currencies = Object.keys(data) currencies = currencies.sort() @@ -22,7 +23,9 @@ $(-> $('#currency').change(-> $('#symbol option').remove() - symbols = Object.keys(data[$(this).val()]) + symbol = $(this).val() + return unless symbol + symbols = Object.keys(data[symbol]) $.each(symbols, (i, v) -> $('#symbol').append("") ) diff --git a/public/js/setup.js b/public/js/setup.js new file mode 100644 index 00000000..56b2f067 --- /dev/null +++ b/public/js/setup.js @@ -0,0 +1,72 @@ +(function() { + var g; + + g = typeof exports !== "undefined" && exports !== null ? exports : this; + + g.proceed = false; + + $(function() { + $('#title').focus(); + return $.getJSON("/js/rates.json", function(data) { + var currencies, user; + currencies = Object.keys(data); + currencies = currencies.sort(); + currencies.pop(); + $.each(currencies, function(i, v) { + return $('#currency').append(""); + }); + $("#currency option[value='CAD']").attr('selected', 'selected'); + user = $('#username').val(); + $('#currency').change(function() { + var symbol, symbols; + $('#symbol option').remove(); + symbol = $(this).val(); + if (!symbol) { + return; + } + symbols = Object.keys(data[symbol]); + $.each(symbols, function(i, v) { + return $('#symbol').append(""); + }); + switch ($(this).val()) { + case 'CAD': + return $("#symbol option[value='quadrigacx']").attr('selected', 'selected'); + case 'USD': + return $("#symbol option[value='bitstamp']").attr('selected', 'selected'); + } + }).change(); + $('#address').change(function() { + if (check_address($(this).val())) { + return $(this).css('color', 'black'); + } else { + return $(this).css('color', 'red'); + } + }); + $('#confirm').blur(function() { + $('#confirm_error').remove(); + if ($('#password').val() !== $('#confirm').val()) { + $('#password, #confirm').parent().addClass('has-error'); + return $('#confirm').parent().after('
Passwords don\'t match
'); + } else { + return $('#password, #confirm').parent().removeClass('has-error'); + } + }); + $('#setup').submit(function() { + if ($('.has-error').length()) { + return false; + } + }); + if (user) { + $('#setup').attr('action', "/" + user + "/update").attr('method', 'post'); + return $.getJSON("/" + user + ".json", function(data) { + $('#title').val(data.title); + $('#logo').val(data.logo); + $('#address').val(data.address); + $("#symbol option[value='" + data.symbol + "']").attr('selected', 'selected'); + return $('#commission').val(data.commission); + }); + } + }); + }); + +}).call(this); -- cgit v1.2.3