/******************
* APP FUNCTIONALITY
******************/
//access electron from here
const remote = require('electron').remote;
//user settings
const settings = require('electron-settings');
//default coins
if(settings.has('user.coins')) {
//do nothing because coins already set
}
else {
settings.set('user', {
coins: 'BTC,ETH,LTC'
});
}
//default base currency
if(settings.has('user.currency')) {
//do nothing because currency already set
}
else {
settings.set('user.currency', 'USD');
}
/* Base Currency */
base = settings.get('user.currency'); // get the user's base currency
var currSel = document.getElementById('base'); //select the currency select box
currSel.value = settings.get('user.currency'); //select the option that corresponds to the user's currency
setBase = function() {
//selected base currency
var sel = document.getElementById('base');
var x = sel.selectedIndex;
var y = sel.options;
base = y[x].text;
settings.set('user.currency', base); //save the user's selection
updateData(); //immediately reflect the changed currency
};
//Functions for creating/appending elements
function createNode(element) {
return document.createElement(element);
}
function append(parent, el) {
return parent.appendChild(el);
}
const ul = document.getElementById('prices'); // Get the list where we will place coins
const portfolio_ul = document.getElementById('portfolio-list');;
var url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=crypto-price-widget';
var pinCheck = document.getElementById("pin-to-top");
function clearData() {
ul.innerHTML = '';
clearTimeout(appRefresh);
}
function initData() {
//need to redeclare the url variable here to grab the latest user coins, etc.
var url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=crypto-price-widget';
fetch(url)
.then(
function(response) {
// Examine the response
response.json().then(function(data) {
//console.log(url);
let pricesDISPLAY = data.DISPLAY; // display for everything except coin symbol
let pricesRAW = data.RAW; // raw to get "BTC" instead of bitcoin symbol
var i = 0;
for (let key of Object.keys(pricesDISPLAY)) {
let coin = pricesDISPLAY[key];
//console.log(coin);
let li = createNode('li'),
span = createNode('span');
sym = createNode('span');
li.setAttribute("class", "price");
li.setAttribute("id", "coin-"+[key]);
span.setAttribute("class", "draggable");
//when adding a new coin, default sortorder to 999
if( settings.get(li.id+'.order') == null) {
settings.set(li.id+'.order', 999);
li.setAttribute("sortorder", 999);
}
else {
li.setAttribute("sortorder", settings.get(li.id+'.order'));
}
append(li, span);
append(ul, li);
i++;
} //for
//sort your coins
sortable('#prices', {
handle: 'span'
})[0].addEventListener('sortstop', function(e) {
// Declare variables
var ul, ulPortfolio, li, liPortfolio, i;
ul = document.getElementById("prices");
ulPortfolio = document.getElementById("portfolio-list");
li = ul.getElementsByTagName('li');
liPortfolio = ulPortfolio.getElementsByTagName('li');
// Loop through all list items
for (i = 0; i < li.length; i++) {
li[i].setAttribute("sortorder", i);
var elementID = li[i].id;
//alert(elementID);
settings.set(elementID, { // coin-BTC
order: li[i].getAttribute('sortorder')
});
//alert(settings.get(elementID + '.order'));
} //for
//alert(settings.get('coin.'+e+'.order'));
}); //sortable
//Pin to Top - settings check - immediately set checkbox and window to saved state
if(settings.get('user.pinToTop') == 'yes') {
pinCheck.checked = true;
remote.getCurrentWindow().setAlwaysOnTop(true);
} else {
pinCheck.checked = false;
remote.getCurrentWindow().setAlwaysOnTop(false);
}
sortChildren(
document.getElementById('prices'),
function(li) { return +li.getAttribute('sortorder') }
);
sortChildren(
document.getElementById('portfolio-list'),
function(li) { return +li.getAttribute('sortorder') }
);
}); //response.json
updateData();
} //function(response)
) //.then
.catch(function(err) {
console.log('Unable to connect!');
var mainDiv = document.getElementById("main");
var errorDiv = document.createElement('div');
errorDiv.className = 'error';
errorDiv.innerHTML = '
Uh-oh! Looks like you're offline.
\
\
Reconnect, then reload the app.
\
';
document.getElementById('main').appendChild(errorDiv);
});//catch
}//initData
function updateData() {
//need to redeclare the url variable here to grab the latest user coins, etc.
var url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=crypto-price-widget';
/*
** What data needs to be grabbed/changed?
** Base currency
** Coin price
** % change
** Portfolio - Coin price affects current value / total
*/
//console.log(settings.get('user.coins'));
fetch(url)
.then(
function(response) {
// Examine the text in the response
response.json().then(function(data) {
let pricesDISPLAY = data.DISPLAY; // display for everything except coin symbol
let pricesRAW = data.RAW; // raw to get "BTC" instead of bitcoin symbol
let portfolioSum = 0;
// Chart labels
var chartLabels = [];
// Chart data
var chartData = [];
// Chart colors - need to match these colors to the coin in a future release
var chartColors = [
'#FF9F1C',
'#2EC4B6',
'#E71D36',
'#011627',
'#FDFFFC',
'#D31EE8',
'#0288D1',
'#5FC42D',
'#E64A19',
'#0097A7',
'#FBC02D',
'#00796B',
'#388E3C',
'#689F38',
'#303F9F',
'#C2185B',
'#FFA000',
'#D32F2F',
'#C2185B',
'#fff'
];
for (let key of Object.keys(pricesRAW)) {
let coinDISPLAY = pricesDISPLAY[key];
let coinDISPLAYchange = coinDISPLAY[base].CHANGEPCT24HOUR;
let coinRAW = pricesRAW[key];
//console.log(coinDISPLAY);
let li = document.getElementById("coin-"+[key]),
span = document.querySelector("#coin-"+[key]+" span");
let coinSymbol = coinRAW[base].FROMSYMBOL;
let coinRate = coinDISPLAY[base].PRICE.replace(/ /g,''); //.replace(/ /g,'') removes space after $
//replace currencies that have no symbols with easier to read formats
if(coinRate.includes("AUD")) { coinRate = coinRate.replace("AUD", "A$"); }
if(coinRate.includes("CAD")) { coinRate = coinRate.replace("CAD", "C$"); }
if(coinRate.includes("HKD")) { coinRate = coinRate.replace("HKD", "HK$"); }
if(coinRate.includes("MXN")) { coinRate = coinRate.replace("MXN", "$"); }
if(coinRate.includes("NOK")) { coinRate = coinRate.replace("NOK", "kr"); }
if(coinRate.includes("NZD")) { coinRate = coinRate.replace("NZD", "NZ$"); }
if(coinRate.includes("SEK")) { coinRate = coinRate.replace("SEK", "kr"); }
if(coinRate.includes("SGD")) { coinRate = coinRate.replace("SGD", "S$"); }
if(coinRate.includes("TRY")) { coinRate = coinRate.replace("TRY", "₺"); }
if(coinRate.includes("ZAR")) { coinRate = coinRate.replace("ZAR", "R"); }
//console.log(span);
span.innerHTML = '' + coinSymbol + ' ' + coinRate + '' + coinDISPLAYchange + '%';
//Price Alert Test - PRO Feature
/*
* Choose crypto
* Choose price
* Choose equals, greater than, or less than price
* Alert set to "on"
* Alert when matches conditions
* When click on notification, alert set to "off"
* Use electron settings, localStorage, or sessionStorage?
* Should this be included in the updateData or separate?
*/
/*
var alerted = localStorage.getItem('alerted') || '';
if(coinSymbol.includes("BTC") && coinRAW[base].PRICE >= "5723" && alerted != 'yes') {
let notif = new window.Notification('Price Alert', {
body: "BTC has gone above 5790!"
});
notif.onclick = () => {
//so it doesn't keep notifying us every 3 seconds.
localStorage.setItem('alerted','yes');
}
}
*/
// % Change
let change = document.querySelector("#coin-"+[key]+" .change");
if(coinDISPLAYchange > 0) {
change.className += " positive";
change.classList.remove("negative");
}
else if(coinDISPLAYchange < 0) {
change.className += " negative";
change.classList.remove("postive");
}
else {
change.classList.remove("postive");
change.classList.remove("negative");
}
// Portfolio
let quantityValue = document.querySelector("#coin-"+[key]+" .quantity-value");
let quantityNumber = settings.get('quantity.'+[key]);
let regp = /[^0-9.-]+/g;
if(quantityNumber != null) {
quantityTotal = parseFloat(coinRate.replace(regp, '')) * parseFloat(quantityNumber.replace(regp, ''));
}
// sum of all total coin values
portfolioSum += quantityTotal;
// put sum into the markup
let portfolioTotalValue = document.querySelector("#portfolio-total-value .value");
// total value for each coin
if(coinRate.includes("Ƀ")) {
//because BTC has 8 decimal places
quantityValue.innerHTML = quantityTotal.toFixed(8);
portfolioTotalValue.innerHTML = portfolioSum.toFixed(8);
}
else if(quantityValue != null) {
//standard currency format
quantityValue.innerHTML = quantityTotal.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
portfolioTotalValue.innerHTML = portfolioSum.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
}
// Chart labels
chartLabels.push(key);
// Chart data
chartData.push(quantityTotal);
} //for
var newChartLabels = chartLabels;
// Chart
var ctx = document.getElementById("portfolioChart");
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
datasets: [{
data: chartData,
backgroundColor: chartColors,
borderColor: '#000',
borderWidth: 0
}],
labels: newChartLabels
},
options: {
animation : false,
responsive: false,
maintainAspectRatio: true,
legend : {
position: 'bottom'
}
}
}); //myChart
}); //response.json().then
} //function(response)
) //then
appRefresh = setTimeout(function(){updateData()}, 5000); // run this once every 5 seconds
} //updateData()
// Let's do this thing!
initData();
// Click on #saveCoins, save the coin selection to the user
document.getElementById('saveCoins').onclick = function(){
var coinForm = document.getElementById('coinlist');
var selchb = getSelectedChbox(coinForm); // gets the array returned by getSelectedChbox()
settings.set('user.coins', selchb);
//clear and reload
clearData();
initData();
}
/***********
* PORTFOLIO
***********/
var portfolio_list_container = document.querySelector('#portfolio-list');
var portfolio_list = settings.get('user.coins');
//generate html from list of coins
for (let key of Object.keys(portfolio_list)) {
let coin = portfolio_list[key];
//console.log(coin);
let li = createNode('li'),
span = createNode('span');
sym = createNode('span');
li.setAttribute("id", "coin-"+[coin]);
li.setAttribute("sortorder", settings.get(li.id+'.order'));
append(li, span);
append(portfolio_ul, li);
if (settings.has('quantity.'+[coin])) {
inputValue = settings.get('quantity.'+[coin]);
}
else {
inputValue = '0';
settings.set('quantity.'+[coin], '0');
}
span.innerHTML = '' + coin + '';
i++;
} //for
// save quantities
document.getElementById('saveQuantities').onclick = function(){
var items = portfolio_ul.getElementsByTagName("input");
for (var i = 0; i < items.length; ++i) {
// do something with items[i], which is a
element
inputName = items[i].getAttribute("name");
inputValue = items[i].value;
//console.log(inputValue);
settings.set(inputName, inputValue);
}
// just reloading the entire app because I have yet to figure out how to add/remove a coin from the primary list without a page reload
//location.reload(false);
}
/***********
* SETTINGS
***********/
// Settings - list of coins
function loadJSON(callback) {
//Stored local version of https://www.cryptocompare.com/api/data/coinlist/ for performance
var file = './coinlist.json';
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', file, true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
} //loadJSON
// Generate the list of all coins
loadJSON(function(response) {
// Parse JSON string into object
var myDiv = document.getElementById("coinlist");
var actual_JSON = JSON.parse(response);
//alert(settings.get('user.coins'));
//console.log(actual_JSON.Data);
//loop through data, get coin info, generate checkbox for each coin
Object.keys(actual_JSON.Data).forEach(function(key) {
//console.log(actual_JSON.Data[key].Name);
//console.log(actual_JSON.Data[key].CoinName);
var li = document.createElement("li");
var checkBox = document.createElement("input");
checkBox.className = "coinCode";
var label = document.createElement("label");
label.className = "coinName";
var div = document.createElement("div");
checkBox.type = "checkbox";
checkBox.value = actual_JSON.Data[key].Name;
checkBox.id = actual_JSON.Data[key].Name;
label.htmlFor = actual_JSON.Data[key].Name;
checkBox.name = "cl[]";
//check the coins the user has already set
var str = String(settings.get('user.coins'));
var split_str = str.split(",");
if (split_str.indexOf(actual_JSON.Data[key].Name) !== -1) {
checkBox.checked = true;
}
myDiv.appendChild(li);
li.appendChild(checkBox);
li.appendChild(label);
label.appendChild(document.createTextNode(actual_JSON.Data[key].CoinName));
label.appendChild(document.createTextNode(' ('+actual_JSON.Data[key].Name+')'));
label.appendChild(div);
}); //forEach
}); //loadJSON
// Returns an array with values of the selected (checked) checkboxes in "frm"
function getSelectedChbox(frm) {
var selchbox = []; // array that will store the value of selected checkboxes
// gets all the input tags in frm, and their number
var inpfields = frm.getElementsByTagName('input');
var nr_inpfields = inpfields.length;
// traverse the inpfields elements, and adds the value of selected (checked) checkbox in selchbox
for(var i=0; i -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
} //for
} //myFunction
//sort by attribute
function sortChildren(wrap, f, isNum) {
var l = wrap.children.length,
arr = new Array(l);
for(var i=0; ib[0] ? 1 : 0; }
);
var par = wrap.parentNode,
ref = wrap.nextSibling;
par.removeChild(wrap);
for(var i=0; i