crypto-price-widget/index.html
2017-09-08 23:13:24 -05:00

779 lines
26 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Latest Crypto Prices</title>
<link href="https://fonts.googleapis.com/css?family=Heebo:100,400" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<style type="text/css">
/*@import url('https://rsms.me/interface/interface.css');*/
body {
background: rgba(0, 0, 0, 0.95);
font-family: 'Inconsolata', monospace;
color: #fff;
margin-top: 5px;
}
ul {
margin: 0;
padding: 0;
}
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
opacity: 0;
}
.titlebar:hover {
opacity: 1;
}
.titlebar .controls {
float: right;
line-height: 0;
}
button {
-webkit-app-region: no-drag;
background: none;
border: none;
outline: none;
}
#close-btn,
#min-btn {
height: 12px;
width: 12px;
background: none;
border: 2px solid #000;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
padding: 0;
}
#close-btn {
border-color: #ff2626;
}
#close-btn:hover {
background: #ff2626;
}
#min-btn {
border-color: #ffbd45;
}
#min-btn:hover {
background: #ffbd45;
}
#settings-btn {
padding: 0;
}
#settings-btn img {
width: 24px;
opacity: 0.5;
}
#settings-btn:hover img {
opacity: 1;
}
ul {
list-style-type: none;
}
#prices {
margin: 0;
padding: 0;
font-size: 28px;
font-weight: 400;
}
#prices li {
margin: 0px 0px 15px 0px;
padding: 0px 0px 15px 0px;
border-bottom: 1px solid #252525;
}
#prices li:last-child {
border-bottom: none;
}
#prices li span {
}
#prices li span.draggable {
width: 100%;
}
#prices li .sym {
border: 1px solid #252525;
border-left-width: 2px;
padding: 0px 5px 0px;
font-family: 'Heebo', sans-serif;
font-size: 12px;
}
#prices li .sym:hover {
cursor: -webkit-grab;
}
/*Symbol Colors*/
#prices li#coin-BTC .sym {
border-left-color: #F9A847;
}
#prices li#coin-XRP .sym {
border-left-color: #0997D2;
}
#prices li#coin-LTC .sym {
border-left-color: #F1F1F1;
}
#prices li#coin-NEO .sym,
#prices li#coin-GAS .sym {
border-left-color: #9CD115;
}
#prices li#coin-OMG .sym {
border-left-color: #1A53F0;
}
#prices li#coin-BCH .sym {
border-left-color: #F7931A;
}
#prices li#coin-DASH .sym {
border-left-color: #0475B6;
}
#prices li#coin-XMR .sym {
border-left-color: #FF6600;
}
#prices li#coin-ETC .sym {
border-left-color: #689274;
}
#prices li#coin-ZEC .sym {
border-left-color: #EFB948;
}
#prices li#coin-GNT .sym {
border-left-color: #00AFBF;
}
#prices li#coin-BAT .sym {
border-left-color: #662F92;
}
#prices li#coin-FCT .sym {
border-left-color: #E3A77D;
}
#prices li#coin-ARK .sym {
border-left-color: #CB0101;
}
#prices li#coin-DOGE .sym {
border-left-color: #BBA034;
}
#prices li#coin-CVC .sym {
border-left-color: #41BB2E;
}
#prices li#coin-MCO .sym {
border-left-color: #82344C;
}
#prices li#coin-UBQ .sym {
border-left-color: #00EA90;
}
#prices li#coin-DNT .sym {
border-left-color: #7CF7FA;
}
#prices li .change {
padding: 2px 3px 2px;
font-size: 12px;
float: right;
margin: 10px 0px 0px;
background: #000;
}
#prices li .change.positive {
color: #b2ff93;
}
#prices li .change.negative {
color: #ff6765;
}
.active {
display: block;
}
.inactive {
display: none;
}
/*Settings Page*/
#settings h3:first-child {
margin-top: 5px;
}
#myInput {
font-family: 'Inconsolata', monospace;
border: none;
padding: 0px 0px 10px;
font-size: 14px;
background: rgba(0, 0, 0, 0);
color: #fff;
outline: none;
border-bottom: 1px solid #252525;
display: block;
width: 100%;
}
#saveCoins {
background-color: #000000;
color: #fff;
border: 1px solid #252525;
padding: 5px 10px;
margin: -1px 0px 0px 0px;
font-family: 'Inconsolata', monospace;
}
#coinlist {
margin: 15px 0px 0px 0px;
padding: 0;
max-height: 218px;
overflow-y: scroll;
}
#coinlist li {
position: relative;
margin: 0px 0px 5px 0px;
}
/* Custom checkboxes inspired by https://codepen.io/sderoij/pen/VvJJwE */
#coinlist label {
height: auto;
width: 100%;
z-index: 0;
display: inline-block;
position: absolute;
top: 0;
left: 0;
text-indent: 24px;
}
#coinlist label div {
height: 12px;
width: 12px;
border: solid 2px rgba(255, 255, 255, 0.6);
margin: 0;
border-radius: 50%;
transform: rotate(45deg);
transition: all 0ms ease-in-out, border 0ms ease 0ms;
position: absolute;
top: 0;
}
#coinlist input:hover + label div {
border-color: rgba(138, 255, 131, 0.9);
}
#coinlist input {
height: auto;
width: 18px;
margin: 0;
opacity: 0;
z-index: 1;
position: relative;
cursor: pointer;
}
#coinlist input:checked + label > div {
border-radius: 0;
border-top: 0;
border-left: 0;
border-color: rgba(138, 255, 131, 0.9);
height: 15px;
width: 12px;
margin-top: -4px;
margin-left: 0px;
transform: rotate(40deg);
transition: all 0ms ease-in-out;
}
#tips {
font-size: 12px;
}
#tips li {
}
.creds {
font-size: 8px;
color: #252525;
margin: 15px 0px 0px 0px;
}
.creds a {
text-decoration: none;
color: #252525;
}
/*Scrollbar*/
::-webkit-scrollbar-corner {
background-color: #000;
}
::-webkit-scrollbar {
background-color: rgba(0, 0, 0, 100);
}
::-webkit-scrollbar {
width: .5em;
height: .5em;
}
::-webkit-scrollbar-thumb:window-inactive,
::-webkit-scrollbar-thumb {
background: #252525;
-webkit-border-radius: 100px;
}
/*Select Boxes*/
.custom-select {
position: relative;
display: inline-block;
}
.custom-select select {
display: inline-block;
border: 1px solid #252525;
padding: 4px 3px 3px 5px;
margin: 0;
font: inherit;
outline: none;
line-height: 1.2;
background: #000000;
-webkit-appearance: none;
width: 145px;
color: #fff;
}
/* for Webkit's CSS-only solution */
@media screen and (-webkit-min-device-pixel-ratio:0) {
.custom-select select {
padding-right:30px;
}
}
/* Since we removed the default focus styles, we have to add our own */
.custom-select select:focus {
-webkit-box-shadow: 0 0 3px 1px #00afc1;
-moz-box-shadow: 0 0 3px 1px #00afc1;
box-shadow: 0 0 3px 1px #00afc1;
}
/* Select arrow styling */
.custom-select:after {
content: "▼";
position: absolute;
top: 0;
right: 0;
bottom: 0;
font-size: 60%;
line-height: 30px;
padding: 0 7px;
background: #252525;
color: white;
pointer-events: none;
}
</style>
</head>
<body>
<header style="-webkit-app-region: drag" class="titlebar">
<div class="controls">
<button id="min-btn"></button>
<button id="close-btn"></button>
</div>
<button id="settings-btn" onclick="toggleSettings()"><img src="images/icons8-Settings.png"></button>
</header>
<div id="main" class="panel active">
<ul id="prices">
</ul>
</div><!-- #main -->
<div id="settings" class="panel inactive">
<h3>Choose Your Coins</h3>
<div id="coinsearch">
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Type here to filter list">
<button type="button" id="saveCoins">Save</button>
<ul id="coinlist">
</ul>
</div><!-- #coinsearch -->
<h3>Choose Your Base Currency</h3>
<label class="custom-select">
<select id="base" onchange="setBase()">
<option value="BTC">BTC</option>
<option value="USD">USD</option>
<!-- 20 most traded currencies - https://en.wikipedia.org/wiki/Template:Most_traded_currencies -->
<option value="AUD">AUD</option>
<option value="BRL">BRL</option>
<option value="CAD">CAD</option>
<option value="CNY">CNY</option>
<option value="EUR">EUR</option>
<option value="GBP">GBP</option>
<option value="HKD">HKD</option>
<option value="INR">INR</option>
<option value="JPY">JPY</option>
<option value="KRW">KRW</option>
<option value="MXN">MXN</option>
<option value="NOK">NOK</option>
<option value="NZD">NZD</option>
<option value="RUB">RUB</option>
<option value="SEK">SEK</option>
<option value="SGD">SGD</option>
<option value="TRY">TRY</option>
<option value="ZAR">ZAR</option>
</select>
</label>
<h3>Tip Jar</h3>
<ul id="tips">
<li>BTC: 17iENfaJkEpxGXW7mgdFh9hGMZV65R2zVL</li>
<li>ETH: 0x68b99868700b33A248de4A62a038a9e3b03DCA21</li>
<li>LTC: La8eCVjzLq8zrJV3LgyU6WtnyQnjs76LFY</li>
<li>DOGE: DFHBdwUbcvGezfgHHbWmH8eLWjAjUhFSZ2</li>
</ul>
<div class="creds">
<div>Icons made by <a href="https://www.flaticon.com/authors/madebyoliver" title="Madebyoliver">Madebyoliver</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
</div>
</div><!-- #settings -->
</body>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
<script>
/******************
* APP FUNCTIONALITY
******************/
//user settings
const settings = require('electron-settings');
settings.set('developer', {
first: 'Nathan',
last: 'Parikh'
});
//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');
}
(function() {
function loadJSON(callback) {
var file = 'https://www.cryptocompare.com/api/data/coinlist/';
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.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
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);
}
// 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<nr_inpfields; i++) {
if(inpfields[i].type == 'checkbox' && inpfields[i].checked == true) selchbox.push(inpfields[i].value);
}
return selchbox;
}
/* Test this function */
//document.getElementById('firstname').innerHTML = settings.get('user.coins');
// 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()
//alert(selchb);
settings.set('user', {
coins: selchb
});
var selectedCoins = settings.get('user.coins');
//document.getElementById('firstname').innerHTML = selectedCoins;
// 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();
}
const ul = document.getElementById('prices'); // Get the list where we will place coins
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=your_app_name';
function initData() {
fetch(url)
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the response
response.json().then(function(data) {
//console.log(data);
let prices = data.DISPLAY;
var i = 0;
for (let key of Object.keys(prices)) {
let coin = prices[key];
//console.log(coin);
let li = createNode('li'),
span = createNode('span');
sym = createNode('span');
li.setAttribute("class", "price");
li.setAttribute("id", "coin-"+[key]);
//alert("coin-"+[key])
//console.log(settings.get('coin.'+[key]+'.order'));
li.setAttribute("sortorder", settings.get(li.id+'.order'));
//alert(settings.get(li.id+'.order'));
append(li, span);
append(ul, li);
i++;
}
//console.log(data.RAW.BTC.USD.PRICE)
sortChildren(
document.getElementById('prices'),
function(li) { return +li.getAttribute('sortorder') }
);
//sort your coins
sortable('#prices', {
handle: 'span'
})[0].addEventListener('sortstop', function(e) {
// Declare variables
var ul, li, i;
ul = document.getElementById("prices");
li = ul.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'));
}
//alert(settings.get('coin.'+e+'.order'));
/*
This event is triggered when the user stopped sorting and the DOM position has changed.
e.detail.item contains the current dragged element.
e.detail.index contains the new index of the dragged element (considering only list items)
e.detail.oldindex contains the old index of the dragged element (considering only list items)
e.detail.elementIndex contains the new index of the dragged element (considering all items within sortable)
e.detail.oldElementIndex contains the old index of the dragged element (considering all items within sortable)
e.detail.startparent contains the element that the dragged item comes from
e.detail.endparent contains the element that the dragged item was added to (new parent)
e.detail.newEndList contains all elements in the list the dragged item was dragged to
e.detail.newStartList contains all elements in the list the dragged item was dragged from
e.detail.oldStartList contains all elements in the list the dragged item was dragged from BEFORE it was dragged from it
*/
}); //sortable
}); //response.json
} //function(response)
) //.then
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
updateData();
}
function updateData() {
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=your_app_name';
fetch(url)
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// 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
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");
span.setAttribute("class", "draggable");
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 = '<span class="sym">' + coinSymbol + '</span> ' + coinRate + '<span class="change">' + coinDISPLAYchange + '%</span>';
// % 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");
}
}
});
}
)
setTimeout(function(){updateData()}, 5000); // run this once every 5 seconds
}
// Let's do this thing!
initData();
/*******
* APP UI
********/
//Window controls
const remote = require('electron').remote;
document.getElementById("close-btn").addEventListener("click", function (e) {
var window = remote.getCurrentWindow();
window.close();
});
document.getElementById("min-btn").addEventListener("click", function (e) {
var window = remote.getCurrentWindow();
window.minimize();
});
//settings tab/icon
function toggleSettings() {
var divs = document.getElementsByClassName('panel'), i;
for (i = 0; i < divs.length; ++i) {
if(divs[i].classList.contains('inactive')) {
divs[i].classList.remove('inactive');
divs[i].classList.add('active');
}
else {
divs[i].classList.remove('active');
divs[i].classList.add('inactive');
}
}//for
}//toggleSettings
//Coin search filter
function myFunction() {
// Declare variables
var input, filter, ul, li, a, i;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("coinlist");
li = ul.getElementsByTagName('li');
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < li.length; i++) {
label = li[i].getElementsByTagName("label")[0];
checkbox = li[i].getElementsByTagName("input")[0].value;
if (label.innerHTML.toUpperCase().indexOf(filter) > -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; i<l; ++i)
arr[i] = [f(wrap.children[i]), wrap.children[i]];
arr.sort(isNum
? function(a,b){ return a[0]-b[0]; }
: function(a,b){ return a[0]<b[0] ? -1 : a[0]>b[0] ? 1 : 0; }
);
var par = wrap.parentNode,
ref = wrap.nextSibling;
par.removeChild(wrap);
for(var i=0; i<l; ++i) wrap.appendChild(arr[i][1]);
par.insertBefore(wrap, ref);
} //sortChildren
</script>
<script src="js/html.sortable.min.js"></script>
</html>