Arranging files
Moved all public/ to docs/ so that github pages can be hosted on docs/ alone - Moved floGlobals.js, lib.js, floCrypto.js, floBlockchainAPI.js, tokenAPI.js, KBucket.js to docs/scripts/ - Renamed api.js to exchangeAPI.js and moved to docs/scripts/ - Moved index.html to docs/ - Moved css components to docs/css - Updated all imports for the above changes. - User pages (index.html) uses floCrypto.js and floBlockchainAPI.js in docs/script dir instead of fetching from cdn
This commit is contained in:
parent
1823a46a98
commit
b229b6b3d5
@ -7,16 +7,18 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RanchiMall market</title>
|
||||
|
||||
<script src="components.js" defer></script>
|
||||
<script src="css/components.js" defer></script>
|
||||
<link rel="stylesheet" href="css/main.min.css">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet">
|
||||
<script src="floGlobals.js"></script>
|
||||
<script src="https://sairajzero.github.io/Standard_Operations/cdn/floCrypto.js"></script>
|
||||
<script src="https://github.com/sairajzero/Standard_Operations/releases/download/test/floBlockchainAPI.js"></script>
|
||||
<script src="KBucket.js"></script>
|
||||
<script src="api.js"></script>
|
||||
<script src="scripts/floGlobals.js"></script>
|
||||
<script src="scripts/lib.js"></script>
|
||||
<script src="scripts/floCrypto.js"></script>
|
||||
<script src="scripts/floBlockchainAPI.js"></script>
|
||||
<script src="scripts/tokenAPI.js"></script>
|
||||
<script src="scripts/KBucket.js"></script>
|
||||
<script src="scripts/exchangeAPI.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="hide-completely">
|
||||
@ -20,55 +20,6 @@ function exchangeAPI(api, options) {
|
||||
})
|
||||
}
|
||||
|
||||
const tokenAPI = {
|
||||
fetch_api: function(apicall) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(floGlobals.tokenURL + apicall);
|
||||
fetch(floGlobals.tokenURL + apicall).then(response => {
|
||||
if (response.ok)
|
||||
response.json().then(data => resolve(data));
|
||||
else
|
||||
reject(response)
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
},
|
||||
getBalance: function(floID, token = 'rupee') {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`)
|
||||
.then(result => resolve(result.balance || 0))
|
||||
.catch(error => reject(error))
|
||||
})
|
||||
},
|
||||
getTx: function(txID) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.fetch_api(`api/v1.0/getTransactionDetails/${txID}`).then(res => {
|
||||
if (res.result === "error")
|
||||
reject(res.description);
|
||||
else if (!res.parsedFloData)
|
||||
reject("Data piece (parsedFloData) missing");
|
||||
else if (!res.transactionDetails)
|
||||
reject("Data piece (transactionDetails) missing");
|
||||
else
|
||||
resolve(res);
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
},
|
||||
sendToken: function(privKey, amount, receiverID, message = "", token = floGlobals.currency) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let senderID = floCrypto.getFloID(privKey);
|
||||
if (typeof amount !== "number" || amount <= 0)
|
||||
return reject("Invalid amount");
|
||||
this.getBalance(senderID, token).then(bal => {
|
||||
if (amount > bal)
|
||||
return reject("Insufficiant token balance");
|
||||
floBlockchainAPI.writeData(senderID, `send ${amount} ${token}# ${message}`, privKey, receiverID)
|
||||
.then(txid => resolve(txid))
|
||||
.catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ResponseError(status, data) {
|
||||
if (data === INVALID_SERVER_MSG)
|
||||
location.reload();
|
||||
902
public/old.html
902
public/old.html
@ -1,902 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RanchiMall market</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet">
|
||||
<script src="floGlobals.js"></script>
|
||||
<script src="https://sairajzero.github.io/Standard_Operations/cdn/floCrypto.js"></script>
|
||||
<script src="https://github.com/sairajzero/Standard_Operations/releases/download/test/floBlockchainAPI.js"></script>
|
||||
<script src="fn.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Current FLO Rate: <span id="cur-rate"></span></div>
|
||||
<form id="login-form">
|
||||
<fieldset>
|
||||
<legend>Login</legend>
|
||||
<input type="password" name="priv-key" placeholder="Enter Private Key" />
|
||||
<input type="text" name="sid" style="display: none;" />
|
||||
<input type="button" name="login" value="login" onclick="UI_evt.login();" /><br />
|
||||
<input type="checkbox" name="remember-me" checked />RememberMe <br />
|
||||
<button type="button" onclick="UI_evt.signup();">Not registered? click here!</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="user-container">
|
||||
<fieldset>
|
||||
<legend>Profile</legend>
|
||||
<span id="user_id"></span><br />
|
||||
FLO: <span id="flo_bal"></span><br />
|
||||
Rupee: <span id="rupee_bal"></span><br />
|
||||
<button onclick="proxy.lock();">Add password lock</button><br />
|
||||
<button onclick="UI_evt.logout();">logout</button>
|
||||
<form id="buy-form">
|
||||
<fieldset>
|
||||
<legend>Buy</legend>
|
||||
<input type="number" name="quantity" placeholder="Enter Quantity" />
|
||||
<input type="number" name="max-price" placeholder="Enter Max Price" />
|
||||
<input type="button" name="buy" value="buy" onclick="UI_evt.buy();" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<form id="sell-form">
|
||||
<fieldset>
|
||||
<legend>Sell</legend>
|
||||
<input type="number" name="quantity" placeholder="Enter Quantity" />
|
||||
<input type="number" name="min-price" placeholder="Enter Min Price" />
|
||||
<input type="button" name="sell" value="sell" onclick="UI_evt.sell();" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<form id="deposit-withdraw-form">
|
||||
<fieldset>
|
||||
<legend>Deposit/Withdraw</legend><br />
|
||||
<input type="number" name="quantity" placeholder="Enter Quantity" />
|
||||
<input type="button" name="deposit-flo" value="Deposit FLO" onclick="UI_evt.depositFLO();" />
|
||||
<input type="button" name="withdraw-flo" value="Withdraw FLO" onclick="UI_evt.withdrawFLO();" />
|
||||
<input type="button" name="deposit-rupee" value="Deposit Rupee" onclick="UI_evt.depositRupee();" />
|
||||
<input type="button" name="withdraw-rupee" value="Withdraw Rupee"
|
||||
onclick="UI_evt.withdrawRupee();" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<button onclick="toggle_view('my-profile');">Toggle</button>
|
||||
<div id="my-profile">
|
||||
<div id="my-orders">
|
||||
<fieldset>
|
||||
<legend>My Orders</legend>
|
||||
<fieldset id="my-buy-orders">
|
||||
<legend>Buying</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Select</th>
|
||||
<th>Quantity</th>
|
||||
<th>Max Price</th>
|
||||
<th>Order Placed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-type="buy"></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset id="my-sell-orders">
|
||||
<legend>Selling</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Select</th>
|
||||
<th>Quantity</th>
|
||||
<th>Min Price</th>
|
||||
<th>Order Placed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-type="sell"></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<button name="cancel-orders" onclick="UI_evt.cancelOrders();">Cancel Orders</button>
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
<div id="my-transactions">
|
||||
<fieldset>
|
||||
<legend>My Transactions</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Sold/Brought</th>
|
||||
<th>To/From</th>
|
||||
<th>Quantity</th>
|
||||
<th>Unit Value</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<button onclick="toggle_view('all-container');">Toggle All</button>
|
||||
<button onclick="refresh();">Refresh</button>
|
||||
<div id="all-container">
|
||||
<div id="buy-orders">
|
||||
<fieldset>
|
||||
<legend>BuyOrders</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Buyer</th>
|
||||
<th>Quantity</th>
|
||||
<th>Max Price</th>
|
||||
<th>Order Placed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div id="sell-orders">
|
||||
<fieldset>
|
||||
<legend>SellOrders</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Seller</th>
|
||||
<th>Quantity</th>
|
||||
<th>Min Price</th>
|
||||
<th>Order Placed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div id="transactions">
|
||||
<fieldset>
|
||||
<legend>Transactions</legend>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Seller</th>
|
||||
<th>Buyer</th>
|
||||
<th>Quantity</th>
|
||||
<th>Unit Value</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<script id="ui_utils">
|
||||
// Global variables
|
||||
const domRefs = {};
|
||||
let timerId;
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
//Checks for internet connection status
|
||||
if (!navigator.onLine)
|
||||
notify(
|
||||
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
||||
"error",
|
||||
{ sound: true }
|
||||
);
|
||||
window.addEventListener("offline", () => {
|
||||
notify(
|
||||
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
||||
"error",
|
||||
{ pinned: true, sound: true }
|
||||
);
|
||||
});
|
||||
window.addEventListener("online", () => {
|
||||
getRef("notification_drawer").clearAll();
|
||||
notify("We are back online.", "success");
|
||||
});
|
||||
|
||||
// Use instead of document.getElementById
|
||||
function getRef(elementId) {
|
||||
if (!domRefs.hasOwnProperty(elementId)) {
|
||||
domRefs[elementId] = {
|
||||
count: 1,
|
||||
ref: null,
|
||||
};
|
||||
return document.getElementById(elementId);
|
||||
} else {
|
||||
if (domRefs[elementId].count < 3) {
|
||||
domRefs[elementId].count = domRefs[elementId].count + 1;
|
||||
return document.getElementById(elementId);
|
||||
} else {
|
||||
if (!domRefs[elementId].ref)
|
||||
domRefs[elementId].ref = document.getElementById(elementId);
|
||||
return domRefs[elementId].ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns dom with specified element
|
||||
function createElement(tagName, options) {
|
||||
const { className, textContent, innerHTML, attributes = {} } = options
|
||||
const elem = document.createElement(tagName)
|
||||
for (let attribute in attributes) {
|
||||
elem.setAttribute(attribute, attributes[attribute])
|
||||
}
|
||||
if (className)
|
||||
elem.className = className
|
||||
if (textContent)
|
||||
elem.textContent = textContent
|
||||
if (innerHTML)
|
||||
elem.innerHTML = innerHTML
|
||||
return elem
|
||||
}
|
||||
|
||||
// Use when a function needs to be executed after user finishes changes
|
||||
const debounce = (callback, wait) => {
|
||||
let timeoutId = null;
|
||||
return (...args) => {
|
||||
window.clearTimeout(timeoutId);
|
||||
timeoutId = window.setTimeout(() => {
|
||||
callback.apply(null, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Limits the rate of function execution
|
||||
function throttle(func, delay) {
|
||||
// If setTimeout is already scheduled, no need to do anything
|
||||
if (timerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule a setTimeout after delay seconds
|
||||
timerId = setTimeout(function () {
|
||||
func();
|
||||
|
||||
// Once setTimeout function execution is finished, timerId = undefined so that in
|
||||
// the next scroll event function execution can be scheduled by the setTimeout
|
||||
timerId = undefined;
|
||||
}, delay);
|
||||
}
|
||||
|
||||
class Stack {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
push(element) {
|
||||
this.items.push(element);
|
||||
}
|
||||
pop() {
|
||||
if (this.items.length == 0)
|
||||
return "Underflow";
|
||||
return this.items.pop();
|
||||
}
|
||||
peek() {
|
||||
return this.items[this.items.length - 1];
|
||||
}
|
||||
}
|
||||
let popupStack = new Stack()
|
||||
let zIndex = 10
|
||||
// function required for popups or modals to appear
|
||||
function showPopup(popupId, pinned) {
|
||||
zIndex++
|
||||
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
||||
popupStack = getRef(popupId).show({ pinned, popupStack })
|
||||
return getRef(popupId);
|
||||
}
|
||||
|
||||
// hides the popup or modal
|
||||
function hidePopup() {
|
||||
if (popupStack.peek() === undefined)
|
||||
return;
|
||||
popupStack.peek().popup.hide()
|
||||
}
|
||||
|
||||
// displays a popup for asking permission. Use this instead of JS confirm
|
||||
const getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => {
|
||||
return new Promise(resolve => {
|
||||
showPopup('confirmation_popup', true)
|
||||
getRef('confirm_title').textContent = title;
|
||||
getRef('confirm_message').textContent = message;
|
||||
let cancelButton = getRef('confirmation_popup').children[2].children[0],
|
||||
submitButton = getRef('confirmation_popup').children[2].children[1]
|
||||
submitButton.textContent = confirmText
|
||||
cancelButton.textContent = cancelText
|
||||
submitButton.onclick = () => {
|
||||
hidePopup()
|
||||
resolve(true);
|
||||
}
|
||||
cancelButton.onclick = () => {
|
||||
hidePopup()
|
||||
resolve(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Function for displaying toast notifications. pass in error for mode param if you want to show an error.
|
||||
function notify(message, mode, options = {}) {
|
||||
const { pinned = false, sound = false } = options
|
||||
let icon
|
||||
switch (mode) {
|
||||
case 'success':
|
||||
icon = `<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"/></svg>`
|
||||
break;
|
||||
case 'error':
|
||||
icon = `<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>`
|
||||
break;
|
||||
}
|
||||
getRef("notification_drawer").push(message, { pinned, icon });
|
||||
if (navigator.onLine && sound) {
|
||||
getRef("notification_sound").currentTime = 0;
|
||||
getRef("notification_sound").play();
|
||||
}
|
||||
if (mode === 'error') {
|
||||
console.error(message)
|
||||
}
|
||||
}
|
||||
|
||||
function getFormattedTime(time, relative) {
|
||||
try {
|
||||
if (String(time).indexOf('_'))
|
||||
time = String(time).split('_')[0]
|
||||
const intTime = parseInt(time)
|
||||
if (String(intTime).length < 13)
|
||||
time *= 1000
|
||||
let timeFrag = new Date(intTime).toString().split(' '),
|
||||
day = timeFrag[0],
|
||||
month = timeFrag[1],
|
||||
date = timeFrag[2],
|
||||
year = timeFrag[3],
|
||||
minutes = new Date(intTime).getMinutes(),
|
||||
hours = new Date(intTime).getHours(),
|
||||
currentTime = new Date().toString().split(' ')
|
||||
|
||||
minutes = minutes < 10 ? `0${minutes}` : minutes
|
||||
let finalHours = ``;
|
||||
if (hours > 12)
|
||||
finalHours = `${hours - 12}:${minutes}`
|
||||
else if (hours === 0)
|
||||
finalHours = `12:${minutes}`
|
||||
else
|
||||
finalHours = `${hours}:${minutes}`
|
||||
|
||||
finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`
|
||||
if (relative) {
|
||||
if (year == currentYear) {
|
||||
if (currentTime[1] === month) {
|
||||
const dateDiff = (parseInt(currentTime[2]) - parseInt(date))
|
||||
if (dateDiff === 0)
|
||||
return `${finalHours}`;
|
||||
else if (dateDiff === 1)
|
||||
return `Yesterday`;
|
||||
else if (dateDiff > 1 && dateDiff < 8)
|
||||
return currentTime[0];
|
||||
else
|
||||
return ` ${date} ${month}`;
|
||||
}
|
||||
else
|
||||
return ` ${date} ${month}`;
|
||||
}
|
||||
else
|
||||
return `${month} ${year}`;
|
||||
}
|
||||
else
|
||||
return `${month} ${date} ${year}, ${finalHours}`;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', e => showPage(window.location.hash))
|
||||
window.addEventListener("load", () => {
|
||||
document.body.classList.remove('hide-completely')
|
||||
document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex)
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.code === 'Escape') {
|
||||
hidePopup()
|
||||
}
|
||||
})
|
||||
document.addEventListener('copy', () => {
|
||||
notify('copied', 'success')
|
||||
})
|
||||
});
|
||||
|
||||
const pagesData = {
|
||||
openedPages: [],
|
||||
params: {}
|
||||
}
|
||||
|
||||
async function showPage(targetPage, options = {}) {
|
||||
const { firstLoad, hashChange } = options
|
||||
let pageId
|
||||
let subPageId
|
||||
let searchParams
|
||||
let params
|
||||
if (targetPage === '') {
|
||||
if (typeof myFloID === "undefined") {
|
||||
pageId = 'landing'
|
||||
} else {
|
||||
pageId = 'home'
|
||||
}
|
||||
} else {
|
||||
if (targetPage.includes('/')) {
|
||||
if (targetPage.includes('?')) {
|
||||
const splitAddress = targetPage.split('?')
|
||||
searchParams = splitAddress.pop()
|
||||
const pages = splitAddress.pop().split('/')
|
||||
pageId = pages[1]
|
||||
subPageId = pages[2]
|
||||
} else {
|
||||
const pages = targetPage.split('/')
|
||||
pageId = pages[1]
|
||||
subPageId = pages[2]
|
||||
}
|
||||
} else {
|
||||
pageId = targetPage
|
||||
}
|
||||
}
|
||||
if (typeof myFloID === "undefined" && !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
||||
if (searchParams) {
|
||||
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
||||
params = Object.fromEntries(urlSearchParams.entries());
|
||||
pagesData.params = params
|
||||
}
|
||||
if (pagesData.lastPage !== pageId) {
|
||||
switch (pageId) {
|
||||
case 'sign_in':
|
||||
setTimeout(() => {
|
||||
getRef('private_key_field').focusIn()
|
||||
}, 0);
|
||||
break;
|
||||
case 'sign_up':
|
||||
const { floID, privKey } = floCrypto.generateNewID()
|
||||
getRef('generated_flo_id').value = floID
|
||||
getRef('generated_private_key').value = privKey
|
||||
break;
|
||||
}
|
||||
document.querySelector('.page:not(.hide-completely)')?.classList.add('hide-completely')
|
||||
getRef(pageId)?.classList.remove('hide-completely')
|
||||
getRef(pageId)?.animate([
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
],
|
||||
{
|
||||
duration: 300,
|
||||
easing: 'ease'
|
||||
})
|
||||
}
|
||||
pagesData.lastPage = pageId
|
||||
if (!pagesData.openedPages.includes(pageId)) {
|
||||
pagesData.openedPages.push(pageId)
|
||||
}
|
||||
}
|
||||
// class based lazy loading
|
||||
class LazyLoader {
|
||||
constructor(container, elementsToRender, renderFn, options = {}) {
|
||||
const { batchSize = 10 } = options
|
||||
|
||||
this.elementsToRender = elementsToRender
|
||||
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||
this.renderFn = renderFn
|
||||
this.intersectionObserver
|
||||
|
||||
this.batchSize = batchSize
|
||||
|
||||
this.lazyContainer = document.querySelector(container)
|
||||
|
||||
this.update = this.update.bind(this)
|
||||
this.render = this.render.bind(this)
|
||||
this.init = this.init.bind(this)
|
||||
this.clear = this.clear.bind(this)
|
||||
}
|
||||
init() {
|
||||
this.intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
observer.disconnect()
|
||||
this.render({ lazyLoad: true })
|
||||
}
|
||||
})
|
||||
}, {
|
||||
threshold: 0.3
|
||||
})
|
||||
this.mutationObserver = new MutationObserver(mutationList => {
|
||||
mutationList.forEach(mutation => {
|
||||
if (mutation.type === 'childList') {
|
||||
if (mutation.addedNodes.length) {
|
||||
this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
this.mutationObserver.observe(this.lazyContainer, {
|
||||
childList: true,
|
||||
})
|
||||
this.render()
|
||||
}
|
||||
update(elementsToRender) {
|
||||
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||
this.render()
|
||||
}
|
||||
render(options = {}) {
|
||||
let { lazyLoad = false } = options
|
||||
const frag = document.createDocumentFragment();
|
||||
if (lazyLoad) {
|
||||
this.updateStartIndex = this.updateEndIndex
|
||||
this.updateEndIndex = this.arrayOfElements.length > this.updateEndIndex + this.batchSize ? this.updateEndIndex + this.batchSize : this.arrayOfElements.length
|
||||
} else {
|
||||
this.intersectionObserver.disconnect()
|
||||
this.lazyContainer.innerHTML = ``;
|
||||
this.updateStartIndex = 0
|
||||
this.updateEndIndex = this.arrayOfElements.length > this.batchSize ? this.batchSize : this.arrayOfElements.length
|
||||
}
|
||||
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
||||
frag.append(this.renderFn(this.arrayOfElements[index]))
|
||||
}
|
||||
this.lazyContainer.append(frag)
|
||||
}
|
||||
clear() {
|
||||
this.intersectionObserver.disconnect()
|
||||
this.mutationObserver.disconnect()
|
||||
this.lazyContainer.innerHTML = ``;
|
||||
}
|
||||
reset() {
|
||||
this.arrayOfElements = (typeof this.elementsToRender === 'function') ? this.elementsToRender() : this.elementsToRender || []
|
||||
this.render()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var user_id; //container for user ID and proxy private-key
|
||||
|
||||
const proxy = {
|
||||
private: null,
|
||||
public: null,
|
||||
lock() {
|
||||
if (!this.private)
|
||||
throw "No proxy key found!";
|
||||
let pwd = prompt("Enter password: ");
|
||||
if (!pwd)
|
||||
alert("Password cannot be empty");
|
||||
else if (pwd.length < 4)
|
||||
alert("Password minimum length is 4");
|
||||
else {
|
||||
let tmp = Crypto.AES.encrypt(this.private, pwd);
|
||||
localStorage.setItem("proxy_secret", "?" + tmp);
|
||||
alert("Successfully locked with Password");
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
localStorage.removeItem("proxy_secret");
|
||||
this.private = null;
|
||||
this.public = null;
|
||||
},
|
||||
set secret(key) {
|
||||
localStorage.setItem("proxy_secret", key);
|
||||
this.private = key;
|
||||
this.public = floCrypto.getPubKeyHex(key);
|
||||
},
|
||||
get secret() {
|
||||
if (this.private)
|
||||
return this.private;
|
||||
try {
|
||||
let tmp = localStorage.getItem("proxy_secret");
|
||||
if (typeof tmp === "string" && tmp.startsWith("?")) {
|
||||
let pwd = prompt("Enter password: ");
|
||||
if (!pwd)
|
||||
throw "Password Required for making transactions";
|
||||
else {
|
||||
try {
|
||||
tmp = Crypto.AES.decrypt(tmp.substring(1), pwd);
|
||||
} catch (error) {
|
||||
throw "Incorrect Password! Password Required for making transactions";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
this.private = tmp;
|
||||
this.public = floCrypto.getPubKeyHex(tmp);
|
||||
return this.private;
|
||||
} catch (error) {
|
||||
alert(error);
|
||||
console.error(error);
|
||||
throw "Unable to fetch Proxy secret";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_view(id) {
|
||||
let element = document.getElementById(id);
|
||||
if (element.style.display === "none")
|
||||
element.style.display = "block";
|
||||
else
|
||||
element.style.display = "none";
|
||||
}
|
||||
|
||||
function list_buy() {
|
||||
getBuyList().then(list => {
|
||||
let container = document.getElementById("buy-orders").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
list.forEach(o => {
|
||||
let row = container.insertRow();
|
||||
row.insertCell().textContent = o.floID;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.maxPrice;
|
||||
row.insertCell().textContent = new Date(o.time_placed);
|
||||
row.dataset["id"] = o.id;
|
||||
});
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
|
||||
function list_sell() {
|
||||
getSellList().then(list => {
|
||||
let container = document.getElementById("sell-orders").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
list.forEach(o => {
|
||||
let row = container.insertRow();
|
||||
row.insertCell().textContent = o.floID;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.minPrice;
|
||||
row.insertCell().textContent = new Date(o.time_placed);
|
||||
row.dataset["id"] = o.id;
|
||||
});
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
|
||||
function list_txns() {
|
||||
getTransactionList().then(list => {
|
||||
let container = document.getElementById("transactions").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
list.forEach(o => {
|
||||
let row = container.insertRow();
|
||||
row.insertCell().textContent = o.seller;
|
||||
row.insertCell().textContent = o.buyer;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.unitValue;
|
||||
row.insertCell().textContent = new Date(o.tx_time);
|
||||
});
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
|
||||
function get_rate() {
|
||||
getRate().then(rate => {
|
||||
console.log("Rate: ", rate);
|
||||
let container = document.getElementById("cur-rate");
|
||||
container.textContent = "Rs " + parseFloat(rate).toFixed(2);
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
|
||||
function refresh(init = false) {
|
||||
if (init)
|
||||
console.info("init");
|
||||
else
|
||||
console.info("refresh");
|
||||
list_buy();
|
||||
list_sell();
|
||||
list_txns();
|
||||
get_rate();
|
||||
if (init || document.getElementById('user-container').style.display === "block")
|
||||
account();
|
||||
}
|
||||
|
||||
function account() {
|
||||
getAccount().then(acc => {
|
||||
console.debug(acc);
|
||||
//Element display
|
||||
document.getElementById("login-form").style.display = "none";
|
||||
document.getElementById('user-container').style.display = "block";
|
||||
document.getElementById("user_id").textContent = acc.floID;
|
||||
user_id = acc.floID;
|
||||
//FLO Balance
|
||||
let flo_total = acc.coins.reduce((a, x) => a + x.quantity, 0);
|
||||
let flo_locked = acc.sellOrders.reduce((a, x) => a + x.quantity, 0);
|
||||
let flo_net = flo_total - flo_locked;
|
||||
console.debug("FLO", flo_total, flo_locked, flo_net);
|
||||
document.getElementById("flo_bal").textContent = flo_net + "(+" + flo_locked + ")";
|
||||
//Rupee Balance
|
||||
let rupee_total = acc.rupee_total;
|
||||
let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0);
|
||||
let rupee_net = rupee_total - rupee_locked;
|
||||
console.debug("RUPEE", rupee_total, rupee_locked, rupee_net);
|
||||
document.getElementById("rupee_bal").textContent = rupee_net + "(+" + rupee_locked + ")";
|
||||
//My buy orders
|
||||
let container = document.getElementById("my-buy-orders").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
acc.buyOrders.forEach(o => {
|
||||
let row = container.insertRow();
|
||||
row.insertCell().innerHTML = `<input type="checkbox">`;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.maxPrice;
|
||||
row.insertCell().textContent = new Date(o.time_placed);
|
||||
row.dataset["id"] = o.id;
|
||||
});
|
||||
//My sell orders
|
||||
container = document.getElementById("my-sell-orders").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
acc.sellOrders.forEach(o => {
|
||||
let row = container.insertRow();
|
||||
row.insertCell().innerHTML = `<input type="checkbox">`;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.minPrice;
|
||||
row.insertCell().textContent = new Date(o.time_placed);
|
||||
row.dataset["id"] = o.id;
|
||||
});
|
||||
//My Transactions
|
||||
container = document.getElementById("my-transactions").getElementsByTagName("tbody")[0];
|
||||
container.innerHTML = '';
|
||||
acc.transactions.forEach(o => {
|
||||
let type, other;
|
||||
if (o.seller === acc.floID) {
|
||||
type = 'Sold To';
|
||||
other = o.buyer === acc.floID ? 'MySelf' : o.buyer;
|
||||
} else if (o.buyer === acc.floID) {
|
||||
type = 'Brought From';
|
||||
other = o.seller;
|
||||
} else
|
||||
return;
|
||||
let row = container.insertRow();
|
||||
row.insertCell().textContent = type;
|
||||
row.insertCell().textContent = other;
|
||||
row.insertCell().textContent = o.quantity;
|
||||
row.insertCell().textContent = o.unitValue;
|
||||
row.insertCell().textContent = new Date(o.tx_time);
|
||||
});
|
||||
try {
|
||||
proxy.secret;
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
}).catch(error => {
|
||||
if (error instanceof ResponseError) {
|
||||
let response = JSON.parse(error.data)
|
||||
console.log(error);
|
||||
console.log(response);
|
||||
document.getElementById('user-container').style.display = "none";
|
||||
document.getElementById("login-form").style.display = "block";
|
||||
document.forms['login-form']["sid"].value = response.sid;
|
||||
proxy.clear();
|
||||
} else
|
||||
console.error(error);
|
||||
})
|
||||
};
|
||||
|
||||
const UI_evt = {};
|
||||
|
||||
UI_evt.signup = function () {
|
||||
let sid = document.forms['login-form']['sid'].value;
|
||||
let privKey = prompt("Enter Private Key of floID to register: ");
|
||||
signUp(privKey, sid).then(result => {
|
||||
console.info(result);
|
||||
alert("Account registered!")
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
alert(error);
|
||||
});
|
||||
};
|
||||
|
||||
UI_evt.logout = function () {
|
||||
logout().then(result => {
|
||||
console.warn(result);
|
||||
proxy.clear();
|
||||
location.reload();
|
||||
}).catch(error => console.error(error));
|
||||
};
|
||||
|
||||
UI_evt.login = function () {
|
||||
let formInputs = document.forms['login-form'];
|
||||
let privKey = formInputs['priv-key'].value;
|
||||
let sid = formInputs['sid'].value;
|
||||
let rememberMe = formInputs['remember-me'].checked;
|
||||
let tmpKey = floCrypto.generateNewID();
|
||||
login(privKey, tmpKey.pubKey, sid, rememberMe).then(result => {
|
||||
console.log(result);
|
||||
proxy.secret = tmpKey.privKey;
|
||||
account();
|
||||
}).catch(error => console.error(error));
|
||||
};
|
||||
|
||||
UI_evt.sell = function () {
|
||||
let formInputs = document.forms['sell-form'];
|
||||
sell(parseFloat(formInputs["quantity"].value), parseFloat(formInputs["min-price"].value), proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
};
|
||||
|
||||
UI_evt.buy = function () {
|
||||
let formInputs = document.forms['buy-form'];
|
||||
buy(parseFloat(formInputs["quantity"].value), parseFloat(formInputs["max-price"].value), proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
};
|
||||
|
||||
UI_evt.cancelOrders = function () {
|
||||
let container = document.getElementById('my-orders');
|
||||
let cancel = [];
|
||||
let inputs = container.getElementsByTagName('input')
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
if (inputs[i].type === "checkbox" && inputs[i].checked) {
|
||||
let row = inputs[i].parentElement.parentElement
|
||||
let id = row.dataset['id'];
|
||||
let type = row.parentElement.dataset['type'];
|
||||
cancel.push([type, id]);
|
||||
}
|
||||
}
|
||||
cancel.forEach(o => cancelOrder(o[0], o[1], proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(o, error)))
|
||||
};
|
||||
|
||||
UI_evt.depositFLO = function () {
|
||||
let formInputs = document.forms['deposit-withdraw-form'];
|
||||
let privKey = prompt("Enter private key");
|
||||
depositFLO(parseFloat(formInputs["quantity"].value), user_id, privKey, proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
}
|
||||
|
||||
UI_evt.depositRupee = function () {
|
||||
let formInputs = document.forms['deposit-withdraw-form'];
|
||||
let privKey = prompt("Enter private key");
|
||||
depositRupee(parseFloat(formInputs["quantity"].value), user_id, privKey, proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
}
|
||||
|
||||
UI_evt.withdrawFLO = function () {
|
||||
let formInputs = document.forms['deposit-withdraw-form'];
|
||||
withdrawFLO(parseFloat(formInputs["quantity"].value), proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
}
|
||||
|
||||
UI_evt.withdrawRupee = function () {
|
||||
let formInputs = document.forms['deposit-withdraw-form'];
|
||||
withdrawRupee(parseFloat(formInputs["quantity"].value), proxy.secret)
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error))
|
||||
.finally(_ => formInputs.reset());
|
||||
}
|
||||
|
||||
refresh(true);
|
||||
</script>
|
||||
<script>
|
||||
getRef('trade_type_selector').addEventListener('change', e => {
|
||||
getRef('get_price').setAttribute('placeholder', e.detail.value === 'buy' ? 'Max price' : 'Min price')
|
||||
getRef('trade_button').textContent = e.detail.value
|
||||
})
|
||||
async function tradeFlo() {
|
||||
const tradeType = getRef('trade_type_selector').value
|
||||
const quantity = parseFloat(getRef('get_quantity').value)
|
||||
const price = parseFloat(getRef('get_price').value)
|
||||
try {
|
||||
if (tradeType === 'buy') {
|
||||
await buy(quantity, price, proxy.secret)
|
||||
} else {
|
||||
await sell(quantity, price, proxy.secret)
|
||||
}
|
||||
notify(`Placed ${tradeType} order`, 'success')
|
||||
}
|
||||
catch (err) {
|
||||
notify(err, 'error')
|
||||
}
|
||||
finally {
|
||||
getRef('trade_form').reset()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1,10 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const getInput = require('./getInput');
|
||||
|
||||
const floGlobals = require('../public/floGlobals');
|
||||
const floGlobals = require('../docs/scripts/floGlobals');
|
||||
require('../src/set_globals');
|
||||
require('../src/lib');
|
||||
require('../src/floCrypto');
|
||||
require('../docs/scripts/lib');
|
||||
require('../docs/scripts/floCrypto');
|
||||
|
||||
console.log(__dirname);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const K_Bucket = require('../../public/KBucket');
|
||||
const K_Bucket = require('../../docs/scripts/KBucket');
|
||||
const slave = require('./slave');
|
||||
const sync = require('./sync');
|
||||
const WebSocket = require('ws');
|
||||
|
||||
10
src/main.js
10
src/main.js
@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
global.floGlobals = require('../public/floGlobals');
|
||||
global.floGlobals = require('../docs/scripts/floGlobals');
|
||||
require('./set_globals');
|
||||
require('./lib');
|
||||
require('./floCrypto');
|
||||
require('./floBlockchainAPI');
|
||||
require('./tokenAPI');
|
||||
require('../docs/scripts/lib');
|
||||
require('../docs/scripts/floCrypto');
|
||||
require('../docs/scripts/floBlockchainAPI');
|
||||
require('../docs/scripts/tokenAPI');
|
||||
|
||||
const Database = require("./database");
|
||||
const App = require('./app');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user