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 {
|
.icon-only {
|
||||||
padding: 0.5rem;
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
padding: 0.4rem;
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
}
|
}
|
||||||
|
.icon-only .icon {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
a:-webkit-any-link:focus-visible {
|
a:-webkit-any-link:focus-visible {
|
||||||
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
@ -712,11 +718,14 @@ menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#main_header {
|
#main_header {
|
||||||
|
grid-area: header;
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||||
|
grid-column: 1/-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
@ -796,11 +805,53 @@ theme-toggle {
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
display: grid;
|
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 {
|
#main_section {
|
||||||
align-content: center;
|
grid-area: main;
|
||||||
|
margin-top: 3vw;
|
||||||
|
align-content: start;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
#main_section > * {
|
#main_section > * {
|
||||||
@ -853,6 +904,22 @@ main {
|
|||||||
.popup__header {
|
.popup__header {
|
||||||
padding: 1rem 1.5rem 0 1.5rem;
|
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 {
|
#input_wrapper {
|
||||||
grid-template-columns: 1fr auto;
|
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 {
|
.icon-only {
|
||||||
padding: 0.5rem;
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
padding: 0.4rem;
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
|
.icon {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a:any-link:focus-visible {
|
a:any-link:focus-visible {
|
||||||
@ -658,11 +664,14 @@ menu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#main_header {
|
#main_header {
|
||||||
|
grid-area: header;
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||||
|
grid-column: 1/-1;
|
||||||
}
|
}
|
||||||
#logo {
|
#logo {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -737,10 +746,48 @@ theme-toggle {
|
|||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
display: grid;
|
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 {
|
#main_section {
|
||||||
align-content: center;
|
grid-area: main;
|
||||||
|
margin-top: 3vw;
|
||||||
|
align-content: start;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
& > * {
|
& > * {
|
||||||
max-width: 36rem;
|
max-width: 36rem;
|
||||||
@ -791,6 +838,21 @@ main {
|
|||||||
.popup__header {
|
.popup__header {
|
||||||
padding: 1rem 1.5rem 0 1.5rem;
|
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 {
|
#input_wrapper {
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
}
|
}
|
||||||
|
|||||||
325
index.html
325
index.html
@ -15,80 +15,94 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||||
<header id="main_header">
|
<sm-popup id="confirmation_popup">
|
||||||
<div id="logo" class="app-brand">
|
<h4 id="confirm_title"></h4>
|
||||||
<svg id="main_logo" class="icon" viewBox="0 0 27.25 32">
|
<p id="confirm_message" class="breakable"></p>
|
||||||
<title>RanchiMall</title>
|
<div class="flex align-center gap-0-5 margin-left-auto">
|
||||||
<path
|
<button class="button cancel-button">Cancel</button>
|
||||||
d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z" />
|
<button class="button button--primary confirm-button">OK</button>
|
||||||
</svg>
|
|
||||||
<div class="app-name">
|
|
||||||
<div class="app-name__company">RanchiMall</div>
|
|
||||||
<h4 class="app-name__title">
|
|
||||||
FLO Ethereum
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button id="meta_mask_status_button" class="button interactive flex align-center hidden"
|
</sm-popup>
|
||||||
data-status="disconnected" onclick="connectToMetaMask()">
|
|
||||||
<div class="icon-wrapper">
|
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="Layer_1" x="0" y="0"
|
|
||||||
version="1.1" viewBox="0 0 318.6 318.6">
|
|
||||||
<style>
|
|
||||||
.st1,
|
|
||||||
.st6 {
|
|
||||||
fill: #e4761b;
|
|
||||||
stroke: #e4761b;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke-linejoin: round
|
|
||||||
}
|
|
||||||
|
|
||||||
.st6 {
|
|
||||||
fill: #f6851b;
|
|
||||||
stroke: #f6851b
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<path fill="#e2761b" stroke="#e2761b" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m274.1 35.5-99.5 73.9L193 65.8z" />
|
|
||||||
<path
|
|
||||||
d="m44.4 35.5 98.7 74.6-17.5-44.3zm193.9 171.3-26.5 40.6 56.7 15.6 16.3-55.3zm-204.4.9L50.1 263l56.7-15.6-26.5-40.6z"
|
|
||||||
class="st1" />
|
|
||||||
<path
|
|
||||||
d="m103.6 138.2-15.8 23.9 56.3 2.5-2-60.5zm111.3 0-39-34.8-1.3 61.2 56.2-2.5zM106.8 247.4l33.8-16.5-29.2-22.8zm71.1-16.5 33.9 16.5-4.7-39.3z"
|
|
||||||
class="st1" />
|
|
||||||
<path fill="#d7c1b3" stroke="#d7c1b3" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m211.8 247.4-33.9-16.5 2.7 22.1-.3 9.3zm-105 0 31.5 14.9-.2-9.3 2.5-22.1z" />
|
|
||||||
<path fill="#233447" stroke="#233447" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m138.8 193.5-28.2-8.3 19.9-9.1zm40.9 0 8.3-17.4 20 9.1z" />
|
|
||||||
<path fill="#cd6116" stroke="#cd6116" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m106.8 247.4 4.8-40.6-31.3.9zM207 206.8l4.8 40.6 26.5-39.7zm23.8-44.7-56.2 2.5 5.2 28.9 8.3-17.4 20 9.1zm-120.2 23.1 20-9.1 8.2 17.4 5.3-28.9-56.3-2.5z" />
|
|
||||||
<path fill="#e4751f" stroke="#e4751f" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m87.8 162.1 23.6 46-.8-22.9zm120.3 23.1-1 22.9 23.7-46zm-64-20.6-5.3 28.9 6.6 34.1 1.5-44.9zm30.5 0-2.7 18 1.2 45 6.7-34.1z" />
|
|
||||||
<path
|
|
||||||
d="m179.8 193.5-6.7 34.1 4.8 3.3 29.2-22.8 1-22.9zm-69.2-8.3.8 22.9 29.2 22.8 4.8-3.3-6.6-34.1z"
|
|
||||||
class="st6" />
|
|
||||||
<path fill="#c0ad9e" stroke="#c0ad9e" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m180.3 262.3.3-9.3-2.5-2.2h-37.7l-2.3 2.2.2 9.3-31.5-14.9 11 9 22.3 15.5h38.3l22.4-15.5 11-9z" />
|
|
||||||
<path fill="#161616" stroke="#161616" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m177.9 230.9-4.8-3.3h-27.7l-4.8 3.3-2.5 22.1 2.3-2.2h37.7l2.5 2.2z" />
|
|
||||||
<path fill="#763d16" stroke="#763d16" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="m278.3 114.2 8.5-40.8-12.7-37.9-96.2 71.4 37 31.3 52.3 15.3 11.6-13.5-5-3.6 8-7.3-6.2-4.8 8-6.1zM31.8 73.4l8.5 40.8-5.4 4 8 6.1-6.1 4.8 8 7.3-5 3.6 11.5 13.5 52.3-15.3 37-31.3-96.2-71.4z" />
|
|
||||||
<path
|
|
||||||
d="m267.2 153.5-52.3-15.3 15.9 23.9-23.7 46 31.2-.4h46.5zm-163.6-15.3-52.3 15.3-17.4 54.2h46.4l31.1.4-23.6-46zm71 26.4 3.3-57.7 15.2-41.1h-67.5l15 41.1 3.5 57.7 1.2 18.2.1 44.8h27.7l.2-44.8z"
|
|
||||||
class="st6" />
|
|
||||||
<script xmlns="" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div id="meta_mask_status">Disconnected</div>
|
|
||||||
</button>
|
|
||||||
<theme-toggle></theme-toggle>
|
|
||||||
</header>
|
|
||||||
<main>
|
<main>
|
||||||
|
<header id="main_header">
|
||||||
|
<div id="logo" class="app-brand">
|
||||||
|
<svg id="main_logo" class="icon" viewBox="0 0 27.25 32">
|
||||||
|
<title>RanchiMall</title>
|
||||||
|
<path
|
||||||
|
d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z" />
|
||||||
|
</svg>
|
||||||
|
<div class="app-name">
|
||||||
|
<div class="app-name__company">RanchiMall</div>
|
||||||
|
<h4 class="app-name__title">
|
||||||
|
FLO Ethereum
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="meta_mask_status_button" class="button interactive flex align-center hidden"
|
||||||
|
data-status="disconnected" onclick="connectToMetaMask()">
|
||||||
|
<div class="icon-wrapper">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="Layer_1" x="0" y="0"
|
||||||
|
version="1.1" viewBox="0 0 318.6 318.6">
|
||||||
|
<style>
|
||||||
|
.st1,
|
||||||
|
.st6 {
|
||||||
|
fill: #e4761b;
|
||||||
|
stroke: #e4761b;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round
|
||||||
|
}
|
||||||
|
|
||||||
|
.st6 {
|
||||||
|
fill: #f6851b;
|
||||||
|
stroke: #f6851b
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path fill="#e2761b" stroke="#e2761b" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m274.1 35.5-99.5 73.9L193 65.8z" />
|
||||||
|
<path
|
||||||
|
d="m44.4 35.5 98.7 74.6-17.5-44.3zm193.9 171.3-26.5 40.6 56.7 15.6 16.3-55.3zm-204.4.9L50.1 263l56.7-15.6-26.5-40.6z"
|
||||||
|
class="st1" />
|
||||||
|
<path
|
||||||
|
d="m103.6 138.2-15.8 23.9 56.3 2.5-2-60.5zm111.3 0-39-34.8-1.3 61.2 56.2-2.5zM106.8 247.4l33.8-16.5-29.2-22.8zm71.1-16.5 33.9 16.5-4.7-39.3z"
|
||||||
|
class="st1" />
|
||||||
|
<path fill="#d7c1b3" stroke="#d7c1b3" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m211.8 247.4-33.9-16.5 2.7 22.1-.3 9.3zm-105 0 31.5 14.9-.2-9.3 2.5-22.1z" />
|
||||||
|
<path fill="#233447" stroke="#233447" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m138.8 193.5-28.2-8.3 19.9-9.1zm40.9 0 8.3-17.4 20 9.1z" />
|
||||||
|
<path fill="#cd6116" stroke="#cd6116" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m106.8 247.4 4.8-40.6-31.3.9zM207 206.8l4.8 40.6 26.5-39.7zm23.8-44.7-56.2 2.5 5.2 28.9 8.3-17.4 20 9.1zm-120.2 23.1 20-9.1 8.2 17.4 5.3-28.9-56.3-2.5z" />
|
||||||
|
<path fill="#e4751f" stroke="#e4751f" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m87.8 162.1 23.6 46-.8-22.9zm120.3 23.1-1 22.9 23.7-46zm-64-20.6-5.3 28.9 6.6 34.1 1.5-44.9zm30.5 0-2.7 18 1.2 45 6.7-34.1z" />
|
||||||
|
<path
|
||||||
|
d="m179.8 193.5-6.7 34.1 4.8 3.3 29.2-22.8 1-22.9zm-69.2-8.3.8 22.9 29.2 22.8 4.8-3.3-6.6-34.1z"
|
||||||
|
class="st6" />
|
||||||
|
<path fill="#c0ad9e" stroke="#c0ad9e" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m180.3 262.3.3-9.3-2.5-2.2h-37.7l-2.3 2.2.2 9.3-31.5-14.9 11 9 22.3 15.5h38.3l22.4-15.5 11-9z" />
|
||||||
|
<path fill="#161616" stroke="#161616" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m177.9 230.9-4.8-3.3h-27.7l-4.8 3.3-2.5 22.1 2.3-2.2h37.7l2.5 2.2z" />
|
||||||
|
<path fill="#763d16" stroke="#763d16" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m278.3 114.2 8.5-40.8-12.7-37.9-96.2 71.4 37 31.3 52.3 15.3 11.6-13.5-5-3.6 8-7.3-6.2-4.8 8-6.1zM31.8 73.4l8.5 40.8-5.4 4 8 6.1-6.1 4.8 8 7.3-5 3.6 11.5 13.5 52.3-15.3 37-31.3-96.2-71.4z" />
|
||||||
|
<path
|
||||||
|
d="m267.2 153.5-52.3-15.3 15.9 23.9-23.7 46 31.2-.4h46.5zm-163.6-15.3-52.3 15.3-17.4 54.2h46.4l31.1.4-23.6-46zm71 26.4 3.3-57.7 15.2-41.1h-67.5l15 41.1 3.5 57.7 1.2 18.2.1 44.8h27.7l.2-44.8z"
|
||||||
|
class="st6" />
|
||||||
|
<script xmlns="" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div id="meta_mask_status">Disconnected</div>
|
||||||
|
</button>
|
||||||
|
<theme-toggle></theme-toggle>
|
||||||
|
</header>
|
||||||
|
<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">
|
<section id="main_section" class="grid gap-1-5">
|
||||||
<h2>
|
<h2>
|
||||||
Check USDC/USDT balance
|
Check USDC/USDT balance
|
||||||
</h2>
|
</h2>
|
||||||
<sm-form>
|
<sm-form oninvalid="handleInvalidSearch()">
|
||||||
<div id="input_wrapper">
|
<div id="input_wrapper">
|
||||||
<sm-input id="private_key_input" class="password-field flex-1" placeholder="FLO/BTC private key"
|
<sm-input id="private_key_input" class="password-field flex-1" placeholder="FLO/BTC private key"
|
||||||
type="password" data-private-key animate required>
|
type="password" data-private-key animate required>
|
||||||
@ -218,6 +232,7 @@
|
|||||||
<script src="scripts/tap_combined.js" type="text/javascript"></script>
|
<script src="scripts/tap_combined.js" type="text/javascript"></script>
|
||||||
<script src="scripts/keccak.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/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="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 src="scripts/usdc_balance.js" type="text/javascript"> </script>
|
||||||
<script>
|
<script>
|
||||||
@ -240,6 +255,48 @@
|
|||||||
function getRef(elementId) {
|
function getRef(elementId) {
|
||||||
return document.getElementById(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 for displaying toast notifications. pass in error for mode param if you want to show an error.
|
||||||
function notify(message, mode, options = {}) {
|
function notify(message, mode, options = {}) {
|
||||||
let icon
|
let icon
|
||||||
@ -257,6 +314,31 @@
|
|||||||
}
|
}
|
||||||
return getRef("notification_drawer").push(message, { icon, ...options });
|
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) {
|
function createRipple(event, target) {
|
||||||
const circle = document.createElement("span");
|
const circle = document.createElement("span");
|
||||||
const diameter = Math.max(target.clientWidth, target.clientHeight);
|
const diameter = Math.max(target.clientWidth, target.clientHeight);
|
||||||
@ -290,13 +372,16 @@
|
|||||||
}
|
}
|
||||||
function buttonLoader(id, show) {
|
function buttonLoader(id, show) {
|
||||||
const button = typeof id === 'string' ? document.getElementById(id) : id;
|
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 = {
|
const animOptions = {
|
||||||
duration: 200,
|
duration: 200,
|
||||||
fill: 'forwards',
|
fill: 'forwards',
|
||||||
easing: 'ease'
|
easing: 'ease'
|
||||||
}
|
}
|
||||||
if (show) {
|
if (show) {
|
||||||
|
button.disabled = true
|
||||||
button.parentNode.append(document.createElement('sm-spinner'))
|
button.parentNode.append(document.createElement('sm-spinner'))
|
||||||
button.animate([
|
button.animate([
|
||||||
{
|
{
|
||||||
@ -307,7 +392,17 @@
|
|||||||
},
|
},
|
||||||
], animOptions)
|
], animOptions)
|
||||||
} else {
|
} 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')
|
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
||||||
if (potentialTarget) potentialTarget.remove();
|
if (potentialTarget) potentialTarget.remove();
|
||||||
}
|
}
|
||||||
@ -332,7 +427,7 @@
|
|||||||
if (!value) return { isValid: false, errorText: 'Please enter a private key' }
|
if (!value) return { isValid: false, errorText: 'Please enter a private key' }
|
||||||
return {
|
return {
|
||||||
isValid: floCrypto.getPubKeyHex(value),
|
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"));
|
createRipple(e, e.target.closest("button, .interactive"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
compactIDB.initDB('floEthereum', {
|
||||||
|
contacts: {}
|
||||||
|
}).then((result) => {
|
||||||
|
renderSearchedAddressList()
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(error)
|
||||||
|
})
|
||||||
connectToMetaMask().then(() => {
|
connectToMetaMask().then(() => {
|
||||||
// setMetaMaskStatus(window.ethereum.isConnected())
|
// setMetaMaskStatus(window.ethereum.isConnected())
|
||||||
window.ethereum.on('networkChanged', (networkId) => {
|
window.ethereum.on('chainChanged', (networkId) => {
|
||||||
if (networkId !== '1') {
|
if (networkId !== '1') {
|
||||||
getRef('error__title').textContent = 'Please switch MetaMask to Ethereum Mainnet'
|
getRef('error__title').textContent = 'Please switch MetaMask to Ethereum Mainnet'
|
||||||
getRef('main_section').classList.add('hidden')
|
getRef('main_section').classList.add('hidden')
|
||||||
@ -414,18 +516,60 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
function checkBalance() {
|
function renderSearchedAddressList() {
|
||||||
const keyToConvert = document.querySelector('[data-private-key]').value.trim()
|
compactIDB.readAllData('contacts').then(contacts => {
|
||||||
if (/^[0-9a-fA-F]{64}$/.test(keyToConvert)) {
|
if (Object.keys(contacts).length === 0) {
|
||||||
keyToConvert = coinjs.privkey2wif(keyToConvert)
|
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;
|
||||||
|
ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
|
||||||
|
floAddress = floCrypto.getFloID(keyToConvert)
|
||||||
}
|
}
|
||||||
const ethPrivateKey = coinjs.wif2privkey(keyToConvert).privkey;
|
|
||||||
const ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
|
|
||||||
const floAddress = floCrypto.getFloID(keyToConvert)
|
|
||||||
if (!ethAddress) return
|
if (!ethAddress) return
|
||||||
buttonLoader('check_balance_button', true)
|
buttonLoader('check_balance_button', true)
|
||||||
Promise.all([checkUSDCBalance(ethAddress), checkUSDTBalance(ethAddress)]).then(([usdcBalance, usdtBalance]) => {
|
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('eth_address').value = ethAddress
|
||||||
getRef('flo_address').value = floAddress
|
getRef('flo_address').value = floAddress
|
||||||
getRef('usdc_balance').textContent = `${ethers.utils.formatUnits(usdcBalance, 6)} USDC`
|
getRef('usdc_balance').textContent = `${ethers.utils.formatUnits(usdcBalance, 6)} USDC`
|
||||||
@ -451,6 +595,27 @@
|
|||||||
buttonLoader('check_balance_button', false)
|
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>
|
</script>
|
||||||
</body>
|
</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