Added balance checking history
This commit is contained in:
parent
6fa3d33e6e
commit
56e8e28d7a
73
css/main.css
73
css/main.css
@ -198,10 +198,16 @@ button:disabled {
|
||||
}
|
||||
|
||||
.icon-only {
|
||||
padding: 0.5rem;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
padding: 0.4rem;
|
||||
border-radius: 0.3rem;
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
.icon-only .icon {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
a:-webkit-any-link:focus-visible {
|
||||
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||
@ -712,11 +718,14 @@ menu {
|
||||
}
|
||||
|
||||
#main_header {
|
||||
grid-area: header;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
|
||||
#logo {
|
||||
@ -796,11 +805,53 @@ theme-toggle {
|
||||
|
||||
main {
|
||||
display: grid;
|
||||
min-height: calc(100% - 5rem);
|
||||
height: 100%;
|
||||
grid-template-rows: auto auto 1fr;
|
||||
grid-template-areas: "header" "main" "search-history";
|
||||
}
|
||||
|
||||
aside {
|
||||
grid-area: search-history;
|
||||
view-transition-name: search-history;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
aside > * {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
aside h4 {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.contact {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.contact sm-chips {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
padding: 0.2rem 0.3rem;
|
||||
border-radius: 0.5rem;
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
.contact sm-chip {
|
||||
--padding: 0.3rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
--border-radius: 0.3rem;
|
||||
}
|
||||
.contact sm-copy {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#main_section {
|
||||
align-content: center;
|
||||
grid-area: main;
|
||||
margin-top: 3vw;
|
||||
align-content: start;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
#main_section > * {
|
||||
@ -853,6 +904,22 @@ main {
|
||||
.popup__header {
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
main {
|
||||
grid-template-columns: 22rem 1fr;
|
||||
grid-template-areas: "header header" "search-history main";
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
aside {
|
||||
border-right: solid thin rgba(var(--text-color), 0.3);
|
||||
overflow-y: auto;
|
||||
}
|
||||
aside h4 {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
z-index: 1;
|
||||
}
|
||||
#input_wrapper {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -185,9 +185,15 @@ button:disabled {
|
||||
}
|
||||
|
||||
.icon-only {
|
||||
padding: 0.5rem;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
padding: 0.4rem;
|
||||
border-radius: 0.3rem;
|
||||
aspect-ratio: 1/1;
|
||||
.icon {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
a:any-link:focus-visible {
|
||||
@ -658,11 +664,14 @@ menu {
|
||||
}
|
||||
}
|
||||
#main_header {
|
||||
grid-area: header;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
#logo {
|
||||
color: inherit;
|
||||
@ -737,10 +746,48 @@ theme-toggle {
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
min-height: calc(100% - 5rem);
|
||||
height: 100%;
|
||||
grid-template-rows: auto auto 1fr;
|
||||
grid-template-areas: "header" "main" "search-history";
|
||||
}
|
||||
aside {
|
||||
grid-area: search-history;
|
||||
view-transition-name: search-history;
|
||||
& > * {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
h4 {
|
||||
padding: 1rem;
|
||||
}
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
.contact {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
sm-chips {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
padding: 0.2rem 0.3rem;
|
||||
border-radius: 0.5rem;
|
||||
width: fit-content;
|
||||
}
|
||||
sm-chip {
|
||||
--padding: 0.3rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
--border-radius: 0.3rem;
|
||||
}
|
||||
sm-copy {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
#main_section {
|
||||
align-content: center;
|
||||
grid-area: main;
|
||||
margin-top: 3vw;
|
||||
align-content: start;
|
||||
padding: 1.5rem;
|
||||
& > * {
|
||||
max-width: 36rem;
|
||||
@ -791,6 +838,21 @@ main {
|
||||
.popup__header {
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
main {
|
||||
grid-template-columns: 22rem 1fr;
|
||||
grid-template-areas: "header header" "search-history main";
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
aside {
|
||||
border-right: solid thin rgba(var(--text-color), 0.3);
|
||||
overflow-y: auto;
|
||||
h4 {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
#input_wrapper {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
185
index.html
185
index.html
@ -15,6 +15,15 @@
|
||||
|
||||
<body>
|
||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||
<sm-popup id="confirmation_popup">
|
||||
<h4 id="confirm_title"></h4>
|
||||
<p id="confirm_message" class="breakable"></p>
|
||||
<div class="flex align-center gap-0-5 margin-left-auto">
|
||||
<button class="button cancel-button">Cancel</button>
|
||||
<button class="button button--primary confirm-button">OK</button>
|
||||
</div>
|
||||
</sm-popup>
|
||||
<main>
|
||||
<header id="main_header">
|
||||
<div id="logo" class="app-brand">
|
||||
<svg id="main_logo" class="icon" viewBox="0 0 27.25 32">
|
||||
@ -83,12 +92,17 @@
|
||||
</button>
|
||||
<theme-toggle></theme-toggle>
|
||||
</header>
|
||||
<main>
|
||||
<aside class="flex flex-direction-column">
|
||||
<h4>
|
||||
Searched addresses
|
||||
</h4>
|
||||
<ul id="searched_addresses_list" class="grid gap-0-5"></ul>
|
||||
</aside>
|
||||
<section id="main_section" class="grid gap-1-5">
|
||||
<h2>
|
||||
Check USDC/USDT balance
|
||||
</h2>
|
||||
<sm-form>
|
||||
<sm-form oninvalid="handleInvalidSearch()">
|
||||
<div id="input_wrapper">
|
||||
<sm-input id="private_key_input" class="password-field flex-1" placeholder="FLO/BTC private key"
|
||||
type="password" data-private-key animate required>
|
||||
@ -218,6 +232,7 @@
|
||||
<script src="scripts/tap_combined.js" type="text/javascript"></script>
|
||||
<script src="scripts/keccak.js" type="text/javascript"></script>
|
||||
<script src="scripts/floEthereum.js" type="text/javascript"></script>
|
||||
<script src="scripts/compactIDB.js" type="text/javascript"></script>
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.6.umd.min.js" type="text/javascript"> </script>
|
||||
<script src="scripts/usdc_balance.js" type="text/javascript"> </script>
|
||||
<script>
|
||||
@ -240,6 +255,48 @@
|
||||
function getRef(elementId) {
|
||||
return document.getElementById(elementId)
|
||||
}
|
||||
let zIndex = 50
|
||||
// function required for popups or modals to appear
|
||||
function openPopup(popupId, pinned) {
|
||||
zIndex++
|
||||
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
||||
getRef(popupId).show({ pinned })
|
||||
return getRef(popupId);
|
||||
}
|
||||
|
||||
// hides the popup or modal
|
||||
function closePopup() {
|
||||
if (popupStack.peek() === undefined)
|
||||
return;
|
||||
popupStack.peek().popup.hide()
|
||||
}
|
||||
|
||||
document.addEventListener('popupopened', async e => {
|
||||
switch (e.target.id) {
|
||||
case 'saved_ids_popup':
|
||||
const allSavedIds = await getArrayOfSavedIds()
|
||||
const renderedIds = renderContactPickerList(allSavedIds)
|
||||
renderElem(getRef('saved_ids_picker_list'), html`${renderedIds}`)
|
||||
getRef('search_saved_ids_picker').focusIn()
|
||||
break;
|
||||
}
|
||||
})
|
||||
document.addEventListener('popupclosed', e => {
|
||||
zIndex--
|
||||
switch (e.target.id) {
|
||||
case 'saved_ids_popup':
|
||||
renderElem(getRef('saved_ids_picker_list'), html``)
|
||||
getRef('search_saved_ids_picker').value = ''
|
||||
floGlobals.addressSelectorTarget = null
|
||||
break;
|
||||
case 'transaction_result_popup':
|
||||
renderElem(getRef('transaction_result'), html``)
|
||||
break;
|
||||
case 'retrieve_flo_id_popup':
|
||||
getRef('recovered_flo_id_wrapper').classList.add('hidden')
|
||||
break;
|
||||
}
|
||||
})
|
||||
//Function for displaying toast notifications. pass in error for mode param if you want to show an error.
|
||||
function notify(message, mode, options = {}) {
|
||||
let icon
|
||||
@ -257,6 +314,31 @@
|
||||
}
|
||||
return getRef("notification_drawer").push(message, { icon, ...options });
|
||||
}
|
||||
// displays a popup for asking permission. Use this instead of JS confirm
|
||||
const getConfirmation = (title, options = {}) => {
|
||||
return new Promise(resolve => {
|
||||
const { message = '', cancelText = 'Cancel', confirmText = 'OK', danger = false } = options
|
||||
openPopup('confirmation_popup', true)
|
||||
getRef('confirm_title').innerText = title;
|
||||
getRef('confirm_message').innerText = message;
|
||||
const cancelButton = getRef('confirmation_popup').querySelector('.cancel-button');
|
||||
const confirmButton = getRef('confirmation_popup').querySelector('.confirm-button')
|
||||
confirmButton.textContent = confirmText
|
||||
cancelButton.textContent = cancelText
|
||||
if (danger)
|
||||
confirmButton.classList.add('button--danger')
|
||||
else
|
||||
confirmButton.classList.remove('button--danger')
|
||||
confirmButton.onclick = () => {
|
||||
closePopup()
|
||||
resolve(true);
|
||||
}
|
||||
cancelButton.onclick = () => {
|
||||
closePopup()
|
||||
resolve(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
function createRipple(event, target) {
|
||||
const circle = document.createElement("span");
|
||||
const diameter = Math.max(target.clientWidth, target.clientHeight);
|
||||
@ -290,13 +372,16 @@
|
||||
}
|
||||
function buttonLoader(id, show) {
|
||||
const button = typeof id === 'string' ? document.getElementById(id) : id;
|
||||
button.disabled = show;
|
||||
if (!button) return
|
||||
if (!button.dataset.hasOwnProperty('wasDisabled'))
|
||||
button.dataset.wasDisabled = button.disabled
|
||||
const animOptions = {
|
||||
duration: 200,
|
||||
fill: 'forwards',
|
||||
easing: 'ease'
|
||||
}
|
||||
if (show) {
|
||||
button.disabled = true
|
||||
button.parentNode.append(document.createElement('sm-spinner'))
|
||||
button.animate([
|
||||
{
|
||||
@ -307,7 +392,17 @@
|
||||
},
|
||||
], animOptions)
|
||||
} else {
|
||||
button.getAnimations().forEach(anim => anim.cancel())
|
||||
button.disabled = button.dataset.wasDisabled === 'true';
|
||||
button.animate([
|
||||
{
|
||||
clipPath: 'circle(0)',
|
||||
},
|
||||
{
|
||||
clipPath: 'circle(100%)',
|
||||
},
|
||||
], animOptions).onfinish = (e) => {
|
||||
button.removeAttribute('data-original-state')
|
||||
}
|
||||
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
||||
if (potentialTarget) potentialTarget.remove();
|
||||
}
|
||||
@ -332,7 +427,7 @@
|
||||
if (!value) return { isValid: false, errorText: 'Please enter a private key' }
|
||||
return {
|
||||
isValid: floCrypto.getPubKeyHex(value),
|
||||
errorText: `Invalid private key.<br> It usually starts with "L".`
|
||||
errorText: `Invalid private key.<br> It usually starts with "L" or "R".`
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -363,9 +458,16 @@
|
||||
createRipple(e, e.target.closest("button, .interactive"));
|
||||
}
|
||||
});
|
||||
compactIDB.initDB('floEthereum', {
|
||||
contacts: {}
|
||||
}).then((result) => {
|
||||
renderSearchedAddressList()
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
connectToMetaMask().then(() => {
|
||||
// setMetaMaskStatus(window.ethereum.isConnected())
|
||||
window.ethereum.on('networkChanged', (networkId) => {
|
||||
window.ethereum.on('chainChanged', (networkId) => {
|
||||
if (networkId !== '1') {
|
||||
getRef('error__title').textContent = 'Please switch MetaMask to Ethereum Mainnet'
|
||||
getRef('main_section').classList.add('hidden')
|
||||
@ -414,18 +516,60 @@
|
||||
});
|
||||
}
|
||||
})
|
||||
function checkBalance() {
|
||||
function renderSearchedAddressList() {
|
||||
compactIDB.readAllData('contacts').then(contacts => {
|
||||
if (Object.keys(contacts).length === 0) {
|
||||
renderElem(getRef('searched_addresses_list'), html`<li class="flex align-center justify-center">
|
||||
<p>Your searched addresses will appear here for easier access in future.</p>
|
||||
</li>`)
|
||||
return
|
||||
}
|
||||
const renderedContacts = []
|
||||
for (const floAddress in contacts) {
|
||||
const { ethAddress } = contacts[floAddress]
|
||||
renderedContacts.push(html`
|
||||
<li class="contact" .dataset=${{ floAddress, ethAddress }}>
|
||||
<sm-chips onchange=${e => e.target.closest('.contact').querySelector('sm-copy').value = e.target.value}>
|
||||
<sm-chip value=${floAddress} selected>FLO</sm-chip>
|
||||
<sm-chip value=${ethAddress}>ETH</sm-chip>
|
||||
</sm-chips>
|
||||
<sm-copy value="${floAddress}"></sm-copy>
|
||||
<div class="flex align-center space-between gap-0-5">
|
||||
<button class="button button--small" onclick=${() => deleteContact(floAddress)}>
|
||||
Delete
|
||||
</button>
|
||||
<button class="button button--colored button--small" onclick=${() => checkBalance(ethAddress, floAddress)}>Check balance</button>
|
||||
</div>
|
||||
</li>`)
|
||||
}
|
||||
renderElem(getRef('searched_addresses_list'), html`${renderedContacts}`)
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
function checkBalance(ethAddress, floAddress) {
|
||||
if (!ethAddress) {
|
||||
const keyToConvert = document.querySelector('[data-private-key]').value.trim()
|
||||
if (/^[0-9a-fA-F]{64}$/.test(keyToConvert)) {
|
||||
keyToConvert = coinjs.privkey2wif(keyToConvert)
|
||||
}
|
||||
const ethPrivateKey = coinjs.wif2privkey(keyToConvert).privkey;
|
||||
const ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
|
||||
const floAddress = floCrypto.getFloID(keyToConvert)
|
||||
ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
|
||||
floAddress = floCrypto.getFloID(keyToConvert)
|
||||
}
|
||||
if (!ethAddress) return
|
||||
buttonLoader('check_balance_button', true)
|
||||
Promise.all([checkUSDCBalance(ethAddress), checkUSDTBalance(ethAddress)]).then(([usdcBalance, usdtBalance]) => {
|
||||
console.log(usdcBalance, usdtBalance)
|
||||
compactIDB.readData('contacts', floAddress).then(result => {
|
||||
if (result) return
|
||||
compactIDB.addData('contacts', {
|
||||
ethAddress,
|
||||
}, floAddress).then(() => {
|
||||
renderSearchedAddressList()
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
getRef('eth_address').value = ethAddress
|
||||
getRef('flo_address').value = floAddress
|
||||
getRef('usdc_balance').textContent = `${ethers.utils.formatUnits(usdcBalance, 6)} USDC`
|
||||
@ -451,6 +595,27 @@
|
||||
buttonLoader('check_balance_button', false)
|
||||
})
|
||||
}
|
||||
function handleInvalidSearch() {
|
||||
if (document.startViewTransition)
|
||||
document.startViewTransition(() => {
|
||||
getRef('eth_balance_wrapper').classList.add('hidden')
|
||||
})
|
||||
else {
|
||||
getRef('eth_balance_wrapper').classList.add('hidden')
|
||||
}
|
||||
|
||||
}
|
||||
async function deleteContact(floAddress) {
|
||||
const confirmed = await getConfirmation('Delete contact', {
|
||||
message: 'Are you sure you want to delete this contact?'
|
||||
})
|
||||
if (!confirmed) return
|
||||
compactIDB.removeData('contacts', floAddress).then(() => {
|
||||
renderSearchedAddressList()
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
257
scripts/compactIDB.js
Normal file
257
scripts/compactIDB.js
Normal file
@ -0,0 +1,257 @@
|
||||
(function (EXPORTS) { //compactIDB v2.1.2
|
||||
/* Compact IndexedDB operations */
|
||||
'use strict';
|
||||
const compactIDB = EXPORTS;
|
||||
|
||||
var defaultDB;
|
||||
|
||||
const indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
||||
const IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
|
||||
const IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
|
||||
|
||||
if (!indexedDB) {
|
||||
console.error("Your browser doesn't support a stable version of IndexedDB.");
|
||||
return;
|
||||
}
|
||||
|
||||
compactIDB.setDefaultDB = dbName => defaultDB = dbName;
|
||||
|
||||
Object.defineProperty(compactIDB, 'default', {
|
||||
get: () => defaultDB,
|
||||
set: dbName => defaultDB = dbName
|
||||
});
|
||||
|
||||
function getDBversion(dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
resolve(db.version)
|
||||
db.close()
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
function upgradeDB(dbName, createList = null, deleteList = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getDBversion(dbName).then(version => {
|
||||
var idb = indexedDB.open(dbName, version + 1);
|
||||
idb.onerror = (event) => reject("Error in opening IndexedDB");
|
||||
idb.onupgradeneeded = (event) => {
|
||||
let db = event.target.result;
|
||||
if (createList instanceof Object) {
|
||||
if (Array.isArray(createList)) {
|
||||
let tmp = {}
|
||||
createList.forEach(o => tmp[o] = {})
|
||||
createList = tmp
|
||||
}
|
||||
for (let o in createList) {
|
||||
let obs = db.createObjectStore(o, createList[o].options || {});
|
||||
if (createList[o].indexes instanceof Object)
|
||||
for (let i in createList[o].indexes)
|
||||
obs.createIndex(i, i, createList[o].indexes || {});
|
||||
}
|
||||
}
|
||||
if (Array.isArray(deleteList))
|
||||
deleteList.forEach(o => db.deleteObjectStore(o));
|
||||
resolve('Database upgraded')
|
||||
}
|
||||
idb.onsuccess = (event) => event.target.result.close();
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
compactIDB.initDB = function (dbName, objectStores = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!(objectStores instanceof Object))
|
||||
return reject('ObjectStores must be an object or array')
|
||||
defaultDB = defaultDB || dbName;
|
||||
var idb = indexedDB.open(dbName);
|
||||
idb.onerror = (event) => reject("Error in opening IndexedDB");
|
||||
idb.onsuccess = (event) => {
|
||||
var db = event.target.result;
|
||||
let cList = Object.values(db.objectStoreNames);
|
||||
var obs = {},
|
||||
a_obs = {},
|
||||
d_obs = [];
|
||||
if (!Array.isArray(objectStores))
|
||||
var obs = objectStores
|
||||
else
|
||||
objectStores.forEach(o => obs[o] = {})
|
||||
let nList = Object.keys(obs)
|
||||
for (let o of nList)
|
||||
if (!cList.includes(o))
|
||||
a_obs[o] = obs[o]
|
||||
for (let o of cList)
|
||||
if (!nList.includes(o))
|
||||
d_obs.push(o)
|
||||
if (!Object.keys(a_obs).length && !d_obs.length)
|
||||
resolve("Initiated IndexedDB");
|
||||
else
|
||||
upgradeDB(dbName, a_obs, d_obs)
|
||||
.then(result => resolve(result))
|
||||
.catch(error => reject(error))
|
||||
db.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const openDB = compactIDB.openDB = function (dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var idb = indexedDB.open(dbName);
|
||||
idb.onerror = (event) => reject("Error in opening IndexedDB");
|
||||
idb.onupgradeneeded = (event) => {
|
||||
event.target.result.close();
|
||||
deleteDB(dbName).then(_ => null).catch(_ => null).finally(_ => reject("Datebase not found"))
|
||||
}
|
||||
idb.onsuccess = (event) => resolve(event.target.result);
|
||||
});
|
||||
}
|
||||
|
||||
const deleteDB = compactIDB.deleteDB = function (dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var deleteReq = indexedDB.deleteDatabase(dbName);;
|
||||
deleteReq.onerror = (event) => reject("Error deleting database!");
|
||||
deleteReq.onsuccess = (event) => resolve("Database deleted successfully");
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.writeData = function (obsName, data, key = false, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readwrite").objectStore(obsName);
|
||||
let writeReq = (key ? obs.put(data, key) : obs.put(data));
|
||||
writeReq.onsuccess = (evt) => resolve(`Write data Successful`);
|
||||
writeReq.onerror = (evt) => reject(
|
||||
`Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
|
||||
);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.addData = function (obsName, data, key = false, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readwrite").objectStore(obsName);
|
||||
let addReq = (key ? obs.add(data, key) : obs.add(data));
|
||||
addReq.onsuccess = (evt) => resolve(`Add data successful`);
|
||||
addReq.onerror = (evt) => reject(
|
||||
`Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
|
||||
);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.removeData = function (obsName, key, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readwrite").objectStore(obsName);
|
||||
let delReq = obs.delete(key);
|
||||
delReq.onsuccess = (evt) => resolve(`Removed Data ${key}`);
|
||||
delReq.onerror = (evt) => reject(
|
||||
`Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
|
||||
);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.clearData = function (obsName, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readwrite").objectStore(obsName);
|
||||
let clearReq = obs.clear();
|
||||
clearReq.onsuccess = (evt) => resolve(`Clear data Successful`);
|
||||
clearReq.onerror = (evt) => reject(`Clear data Unsuccessful`);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.readData = function (obsName, key, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readonly").objectStore(obsName);
|
||||
let getReq = obs.get(key);
|
||||
getReq.onsuccess = (evt) => resolve(evt.target.result);
|
||||
getReq.onerror = (evt) => reject(
|
||||
`Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
|
||||
);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
compactIDB.readAllData = function (obsName, dbName = defaultDB) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readonly").objectStore(obsName);
|
||||
var tmpResult = {}
|
||||
let curReq = obs.openCursor();
|
||||
curReq.onsuccess = (evt) => {
|
||||
var cursor = evt.target.result;
|
||||
if (cursor) {
|
||||
tmpResult[cursor.primaryKey] = cursor.value;
|
||||
cursor.continue();
|
||||
} else
|
||||
resolve(tmpResult);
|
||||
}
|
||||
curReq.onerror = (evt) => reject(
|
||||
`Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
|
||||
);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
/* compactIDB.searchData = function (obsName, options = {}, dbName = defaultDB) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readonly").objectStore(obsName);
|
||||
var filteredResult = {}
|
||||
let keyRange;
|
||||
if(options.lowerKey!==null && options.upperKey!==null)
|
||||
keyRange = IDBKeyRange.bound(options.lowerKey, options.upperKey);
|
||||
else if(options.lowerKey!==null)
|
||||
keyRange = IDBKeyRange.lowerBound(options.lowerKey);
|
||||
else if (options.upperKey!==null)
|
||||
keyRange = IDBKeyRange.upperBound(options.upperBound);
|
||||
else if (options.atKey)
|
||||
let curReq = obs.openCursor(keyRange, )
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}*/
|
||||
|
||||
compactIDB.searchData = function (obsName, options = {}, dbName = defaultDB) {
|
||||
options.lowerKey = options.atKey || options.lowerKey || 0
|
||||
options.upperKey = options.atKey || options.upperKey || false
|
||||
options.patternEval = options.patternEval || ((k, v) => true);
|
||||
options.limit = options.limit || false;
|
||||
options.reverse = options.reverse || false;
|
||||
options.lastOnly = options.lastOnly || false
|
||||
return new Promise((resolve, reject) => {
|
||||
openDB(dbName).then(db => {
|
||||
var obs = db.transaction(obsName, "readonly").objectStore(obsName);
|
||||
var filteredResult = {}
|
||||
let curReq = obs.openCursor(
|
||||
options.upperKey ? IDBKeyRange.bound(options.lowerKey, options.upperKey) : IDBKeyRange.lowerBound(options.lowerKey),
|
||||
options.lastOnly || options.reverse ? "prev" : "next");
|
||||
curReq.onsuccess = (evt) => {
|
||||
var cursor = evt.target.result;
|
||||
if (!cursor || (options.limit && options.limit <= Object.keys(filteredResult).length))
|
||||
return resolve(filteredResult); //reached end of key list or limit reached
|
||||
else if (options.patternEval(cursor.primaryKey, cursor.value)) {
|
||||
filteredResult[cursor.primaryKey] = cursor.value;
|
||||
options.lastOnly ? resolve(filteredResult) : cursor.continue();
|
||||
} else
|
||||
cursor.continue();
|
||||
}
|
||||
curReq.onerror = (evt) => reject(`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
|
||||
db.close();
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
})(window.compactIDB = {});
|
||||
File diff suppressed because one or more lines are too long
2
scripts/components.min.js
vendored
2
scripts/components.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user