Update deps and upgrade to latest vaadin. Minor fixes

This commit is contained in:
AlphaX-Projects 2022-02-19 03:23:59 -08:00 committed by GitHub
parent 4f5d3ad138
commit fcdd4c99ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3782 additions and 3900 deletions

View File

@ -9,139 +9,139 @@ const path = require("path");
const alias = require("@rollup/plugin-alias"); const alias = require("@rollup/plugin-alias");
const aliases = { const aliases = {
// 'qortal-ui-crypto': 'node_modules/qortal-ui-crypto/api.js' // 'qortal-ui-crypto': 'node_modules/qortal-ui-crypto/api.js'
}; };
const generateRollupConfig = (inputFile, outputFile) => { const generateRollupConfig = (inputFile, outputFile) => {
return { return {
inputOptions: { inputOptions: {
onwarn: (warning, rollupWarn) => { onwarn(warning, warn) {
if (warning.code !== "CIRCULAR_DEPENDENCY") { if (warning.code === 'THIS_IS_UNDEFINED') return;
rollupWarn(warning); if (warning.code !== 'CIRCULAR_DEPENDENCY') throw new Error(warning.message);
} warn(warning);
}, },
input: inputFile, input: inputFile,
plugins: [ plugins: [
alias({ alias({
// entries: {} // entries: {}
entries: Object.keys(aliases).map((find) => { entries: Object.keys(aliases).map((find) => {
return { return {
find, find,
replacement: aliases[find], replacement: aliases[find],
}; };
}), }),
}), }),
nodeResolve({ nodeResolve({
preferBuiltins: false, preferBuiltins: false,
mainFields: ['module', 'browser'] mainFields: ['module', 'browser']
}), }),
replace({ replace({
preventAssignment: true, preventAssignment: true,
"process.env.NODE_ENV": JSON.stringify("production"), "process.env.NODE_ENV": JSON.stringify("production"),
}), }),
commonjs(), commonjs(),
globals(), globals(),
progress(), progress(),
babel.babel({ babel.babel({
babelHelpers: 'bundled', babelHelpers: 'bundled',
exclude: "node_modules/**", exclude: "node_modules/**",
}), }),
terser({ terser({
compress: true, compress: true,
output: { output: {
comments: false, comments: false,
}, },
}) })
], ],
}, },
outputOptions: { outputOptions: {
file: outputFile, file: outputFile,
format: "umd", format: "umd",
}, },
}; };
}; };
const generateForPlugins = () => { const generateForPlugins = () => {
const configs = [ const configs = [
{ {
in: "plugins/core/main.src.js", in: "plugins/core/main.src.js",
out: "plugins/core/main.js", out: "plugins/core/main.js",
}, },
{ {
in: "plugins/core/trade-portal/trade-portal.src.js", in: "plugins/core/trade-portal/trade-portal.src.js",
out: "plugins/core/trade-portal/trade-portal.js", out: "plugins/core/trade-portal/trade-portal.js",
}, },
{ {
in: "plugins/core/send-coin/send-coin.src.js", in: "plugins/core/send-coin/send-coin.src.js",
out: "plugins/core/send-coin/send-coin.js", out: "plugins/core/send-coin/send-coin.js",
}, },
{ {
in: "plugins/core/wallet/wallet-app.src.js", in: "plugins/core/wallet/wallet-app.src.js",
out: "plugins/core/wallet/wallet-app.js", out: "plugins/core/wallet/wallet-app.js",
}, },
{ {
in: "plugins/core/reward-share/reward-share.src.js", in: "plugins/core/reward-share/reward-share.src.js",
out: "plugins/core/reward-share/reward-share.js", out: "plugins/core/reward-share/reward-share.js",
}, },
{ {
in: "plugins/core/node-management/node-management.src.js", in: "plugins/core/node-management/node-management.src.js",
out: "plugins/core/node-management/node-management.js", out: "plugins/core/node-management/node-management.js",
}, },
{ {
in: "plugins/core/group-management/group-management.src.js", in: "plugins/core/group-management/group-management.src.js",
out: "plugins/core/group-management/group-management.js", out: "plugins/core/group-management/group-management.js",
}, },
// { // {
// in: 'plugins/core/group-management/group-transaction/group-transaction.src.js', // in: 'plugins/core/group-management/group-transaction/group-transaction.src.js',
// out: 'plugins/core/group-management/group-transaction/group-transaction.js' // out: 'plugins/core/group-management/group-transaction/group-transaction.js'
// }, // },
{ {
in: "plugins/core/name-registration/name-registration.src.js", in: "plugins/core/name-registration/name-registration.src.js",
out: "plugins/core/name-registration/name-registration.js", out: "plugins/core/name-registration/name-registration.js",
}, },
{ {
in: "plugins/core/qdn/websites.src.js", in: "plugins/core/qdn/websites.src.js",
out: "plugins/core/qdn/websites.js", out: "plugins/core/qdn/websites.js",
}, },
{ {
in: "plugins/core/qdn/publish/publish.src.js", in: "plugins/core/qdn/publish/publish.src.js",
out: "plugins/core/qdn/publish/publish.js", out: "plugins/core/qdn/publish/publish.js",
}, },
{ {
in: "plugins/core/qdn/browser/browser.src.js", in: "plugins/core/qdn/browser/browser.src.js",
out: "plugins/core/qdn/browser/browser.js", out: "plugins/core/qdn/browser/browser.js",
}, },
{ {
in: "plugins/core/qdn/data-management/data-management.src.js", in: "plugins/core/qdn/data-management/data-management.src.js",
out: "plugins/core/qdn/data-management/data-management.js", out: "plugins/core/qdn/data-management/data-management.js",
}, },
{ {
in: "plugins/core/messaging/messaging.src.js", in: "plugins/core/messaging/messaging.src.js",
out: "plugins/core/messaging/messaging.js", out: "plugins/core/messaging/messaging.js",
}, },
{ {
in: "plugins/core/messaging/chain-messaging/chain-messaging.src.js", in: "plugins/core/messaging/chain-messaging/chain-messaging.src.js",
out: "plugins/core/messaging/chain-messaging/chain-messaging.js", out: "plugins/core/messaging/chain-messaging/chain-messaging.js",
}, },
{ {
in: "plugins/core/messaging/q-chat/q-chat.src.js", in: "plugins/core/messaging/q-chat/q-chat.src.js",
out: "plugins/core/messaging/q-chat/q-chat.js", out: "plugins/core/messaging/q-chat/q-chat.js",
}, },
{ {
in: "plugins/core/minting/minting-info.src.js", in: "plugins/core/minting/minting-info.src.js",
out: "plugins/core/minting/minting-info.js", out: "plugins/core/minting/minting-info.js",
}, },
{ {
in: "plugins/core/puzzles/puzzles.src.js", in: "plugins/core/puzzles/puzzles.src.js",
out: "plugins/core/puzzles/puzzles.js", out: "plugins/core/puzzles/puzzles.js",
}, },
].map((file) => { ].map((file) => {
return generateRollupConfig( return generateRollupConfig(
path.join(__dirname, file.in), path.join(__dirname, file.in),
path.join(__dirname, file.out) path.join(__dirname, file.out)
); );
}); });
return configs; return configs;
}; };
module.exports = generateForPlugins; module.exports = generateForPlugins;

View File

@ -22,7 +22,7 @@
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js" "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.17.2", "@babel/core": "^7.17.5",
"@github/time-elements": "^3.1.2", "@github/time-elements": "^3.1.2",
"@material/mwc-button": "^0.25.3", "@material/mwc-button": "^0.25.3",
"@material/mwc-dialog": "^0.25.3", "@material/mwc-dialog": "^0.25.3",
@ -39,11 +39,11 @@
"@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.1.3", "@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-replace": "^3.1.0", "@rollup/plugin-replace": "^3.1.0",
"@vaadin/vaadin-grid": "^5.9.3", "@vaadin/grid": "^22.0.5",
"epml": "^0.3.3", "epml": "^0.3.3",
"html-escaper": "^3.0.3", "html-escaper": "^3.0.3",
"lit": "^2.1.3", "lit": "^2.2.0",
"rollup": "^2.67.2", "rollup": "^2.67.3",
"rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-progress": "^1.1.2", "rollup-plugin-progress": "^1.1.2",
"rollup-plugin-terser": "^7.0.2" "rollup-plugin-terser": "^7.0.2"

View File

@ -2,11 +2,9 @@ import { LitElement, html, css } from 'lit'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { escape, unescape } from 'html-escaper'; import { escape, unescape } from 'html-escaper';
import { inputKeyCodes } from '../../utils/keyCodes.js'; import { inputKeyCodes } from '../../utils/keyCodes.js'
import './ChatScroller.js' import './ChatScroller.js'
import './TimeAgo.js' import './TimeAgo.js'
import { EmojiPicker } from 'emoji-picker-js'; import { EmojiPicker } from 'emoji-picker-js';
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'

View File

@ -406,7 +406,7 @@ class ChatWelcomePage extends LitElement {
getAddressPublicKey() getAddressPublicKey()
} }
_textMenu(event) { _textMenu(event) {
const getSelectedText = () => { const getSelectedText = () => {
var text = ""; var text = "";
if (typeof window.getSelection != "undefined") { if (typeof window.getSelection != "undefined") {

View File

@ -46,7 +46,6 @@ class TimeAgo extends LitElement {
} }
firstUpdated() { firstUpdated() {
// ...
} }
} }

View File

@ -1,7 +1,6 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ToolTip extends LitElement { class ToolTip extends LitElement {
@ -92,7 +91,6 @@ class ToolTip extends LitElement {
}) })
parentEpml.subscribe('config', c => { parentEpml.subscribe('config', c => {
if (!configLoaded) { if (!configLoaded) {
// setTimeout(getGroupIdFromURL, 1)
configLoaded = true configLoaded = true
} }
this.config = JSON.parse(c) this.config = JSON.parse(c)

View File

@ -6,11 +6,9 @@ import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-textfield' import '@material/mwc-textfield'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js' import '@vaadin/grid/theme/material/all-imports.js'
import '@github/time-elements' import '@github/time-elements'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -143,7 +141,7 @@ class GroupManagement extends LitElement {
<div class="divCard"> <div class="divCard">
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Your Joined Groups</h3> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Your Joined Groups</h3>
<vaadin-grid id="joinedGroupsGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.joinedGroups)}" aria-label="Joined Groups" .items="${this.joinedGroups}" height-by-rows> <vaadin-grid theme="compact" id="joinedGroupsGrid" ?hidden="${this.isEmptyArray(this.joinedGroups)}" .items="${this.joinedGroups}" aria-label="Joined Groups" all-rows-visible>
<vaadin-grid-column header="Name" path="groupName"></vaadin-grid-column> <vaadin-grid-column header="Name" path="groupName"></vaadin-grid-column>
<vaadin-grid-column header="Description" path="description"></vaadin-grid-column> <vaadin-grid-column header="Description" path="description"></vaadin-grid-column>
<vaadin-grid-column width="9.8rem" flex-grow="0" header="Role" .renderer=${(root, column, data) => { <vaadin-grid-column width="9.8rem" flex-grow="0" header="Role" .renderer=${(root, column, data) => {
@ -160,7 +158,7 @@ class GroupManagement extends LitElement {
<div class="divCard"> <div class="divCard">
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Public Groups</h3> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Public Groups</h3>
<vaadin-grid id="publicGroupsGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.publicGroups)}" aria-label="Public Open Groups" .items="${this.publicGroups}" height-by-rows> <vaadin-grid theme="compact" id="publicGroupsGrid" ?hidden="${this.isEmptyArray(this.publicGroups)}" .items="${this.publicGroups}" aria-label="Public Open Groups" all-rows-visible>
<vaadin-grid-column path="groupName"></vaadin-grid-column> <vaadin-grid-column path="groupName"></vaadin-grid-column>
<vaadin-grid-column header="Description" path="description"></vaadin-grid-column> <vaadin-grid-column header="Description" path="description"></vaadin-grid-column>
<vaadin-grid-column path="owner"></vaadin-grid-column> <vaadin-grid-column path="owner"></vaadin-grid-column>
@ -494,18 +492,18 @@ class GroupManagement extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const url = `${nodeUrl}/transactions/unitfee?txType=CREATE_GROUP`; const url = `${nodeUrl}/transactions/unitfee?txType=CREATE_GROUP`;
await fetch(url) await fetch(url)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
return Promise.reject(response); return Promise.reject(response);
}) })
.then((json) => { .then((json) => {
this.createFee = (Number(json) / 1e8).toFixed(8); this.createFee = (Number(json) / 1e8).toFixed(8);
}) })
.catch((response) => { .catch((response) => {
console.log(response.status, response.statusText, 'Need Core Update'); console.log(response.status, response.statusText, 'Need Core Update');
}) })
} }
async unitJoinFee() { async unitJoinFee() {
@ -513,18 +511,18 @@ class GroupManagement extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const url = `${nodeUrl}/transactions/unitfee?txType=JOIN_GROUP`; const url = `${nodeUrl}/transactions/unitfee?txType=JOIN_GROUP`;
await fetch(url) await fetch(url)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
return Promise.reject(response); return Promise.reject(response);
}) })
.then((json) => { .then((json) => {
this.joinFee = (Number(json) / 1e8).toFixed(8); this.joinFee = (Number(json) / 1e8).toFixed(8);
}) })
.catch((response) => { .catch((response) => {
console.log(response.status, response.statusText, 'Need Core Update'); console.log(response.status, response.statusText, 'Need Core Update');
}) })
} }
async unitLeaveFee() { async unitLeaveFee() {
@ -532,18 +530,18 @@ class GroupManagement extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const url = `${nodeUrl}/transactions/unitfee?txType=LEAVE_GROUP`; const url = `${nodeUrl}/transactions/unitfee?txType=LEAVE_GROUP`;
await fetch(url) await fetch(url)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
return Promise.reject(response); return Promise.reject(response);
}) })
.then((json) => { .then((json) => {
this.leaveFee = (Number(json) / 1e8).toFixed(8); this.leaveFee = (Number(json) / 1e8).toFixed(8);
}) })
.catch((response) => { .catch((response) => {
console.log(response.status, response.statusText, 'Need Core Update'); console.log(response.status, response.statusText, 'Need Core Update');
}) })
} }
resetDefaultSettings() { resetDefaultSettings() {

View File

@ -1,19 +1,8 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
// import { render } from 'lit/html.js'
// import { Epml } from '../../../src/epml.js'
import { Epml } from '../../../../epml.js' import { Epml } from '../../../../epml.js'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
// import * as thing from 'time-elements'
// import '@vaadin/vaadin-grid/vaadin-grid.js'
// import '@vaadin/vaadin-grid/theme/material/all-imports.js'
// import '@material/mwc-icon'
// import '@material/mwc-textfield'
// import '@material/mwc-button'
// import '@material/mwc-dialog'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class GroupTransaction extends LitElement { class GroupTransaction extends LitElement {
@ -75,7 +64,6 @@ class GroupTransaction extends LitElement {
} }
.group-transaction-card { .group-transaction-card {
/* margin:12px; */
padding:12px 24px; padding:12px 24px;
background:#fff; background:#fff;
border-radius:2px; border-radius:2px;
@ -132,121 +120,16 @@ class GroupTransaction extends LitElement {
render() { render() {
return html` return html`
<div id="group-transaction-page"> <div id="group-transaction-page">
<div class="group-transaction-card"> <div class="group-transaction-card">
<h2>Group Transaction</h2> <h2>Group Transaction</h2>
<p>${this.addMintingAccountMessage}</p> <p>${this.addMintingAccountMessage}</p>
</div> </div>
</div> </div>
` `
} }
// getMintingAccountGrid() {
// const myGrid = this.shadowRoot.querySelector('#mintingAccountsGrid')
// myGrid.addEventListener('click', (e) => {
// this.tempMintingAccount = myGrid.getEventContext(e).item
// this.shadowRoot.querySelector('#removeMintingAccountDialog').show()
// })
// }
// addPeer(e) {
// this.addPeerLoading = true
// const addPeerAddress = this.shadowRoot.querySelector('#addPeerAddress').value
// parentEpml.request('apiCall', {
// url: `/peers`,
// method: 'POST',
// body: addPeerAddress
// }).then(res => {
// this.addPeerMessage = res.message
// this.addPeerLoading = false
// })
// }
// addMintingAccount(e) {
// this.addMintingAccountLoading = true
// this.addMintingAccountMessage = "Loading..."
// this.addMintingAccountKey = this.shadowRoot.querySelector('#addMintingAccountKey').value
// parentEpml.request('apiCall', {
// url: `/admin/mintingaccounts`,
// method: 'POST',
// body: this.addMintingAccountKey
// }).then(res => {
// if (res === true) {
// this.updateMintingAccounts()
// this.addMintingAccountKey = ''
// this.addMintingAccountMessage = 'Minting Node Added Successfully!'
// this.addMintingAccountLoading = false
// } else {
// this.addMintingAccountKey = ''
// this.addMintingAccountMessage = 'Failed to Add Minting Node!' // Corrected an error here thanks to crow (-_-)
// this.addMintingAccountLoading = false
// }
// })
// }
// updateMintingAccounts() {
// parentEpml.request('apiCall', {
// url: `/admin/mintingaccounts`
// }).then(res => {
// this.mintingAccounts = []
// setTimeout(() => { this.mintingAccounts = res }, 1)
// })
// // setTimeout(updateMintingAccounts, this.config.user.nodeSettings.pingInterval) // Perhaps should be slower...?
// }
// removeMintingAccount(e) {
// this.removeMintingAccountLoading = true
// this.removeMintingAccountMessage = "Loading..."
// this.removeMintingAccountKey = this.shadowRoot.querySelector('#removeMintingAccountKey').value
// this.mintingAccounts.forEach(mintingAccount => {
// if (this.tempMintingAccount.recipientAccount === mintingAccount.recipientAccount) {
// parentEpml.request('apiCall', {
// url: `/admin/mintingaccounts`,
// method: 'DELETE',
// body: this.removeMintingAccountKey
// }).then(res => {
// if (res === true) {
// this.updateMintingAccounts()
// this.removeMintingAccountKey = ''
// this.removeMintingAccountMessage = 'Minting Node Removed Successfully!'
// this.removeMintingAccountLoading = false
// } else {
// this.removeMintingAccountKey = ''
// this.removeMintingAccountMessage = 'Failed to Remove Minting Node!'
// this.removeMintingAccountLoading = false
// }
// })
// }
// })
// }
firstUpdated() { firstUpdated() {
// Call getMintingAccountGrid
// this.getMintingAccountGrid()
// Call updateMintingAccounts
// this.updateMintingAccounts()
const getGroupIdFromURL = () => { const getGroupIdFromURL = () => {
let tempUrl = document.location.href let tempUrl = document.location.href
let decodeTempUrl = decodeURI(tempUrl) let decodeTempUrl = decodeURI(tempUrl)
@ -276,7 +159,6 @@ class GroupTransaction extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
} }

View File

@ -4,6 +4,30 @@
<head> <head>
<link rel="stylesheet" href="/font/material-icons.css"> <link rel="stylesheet" href="/font/material-icons.css">
<style> <style>
html {
--scrollbarBG: #a1a1a1;
--thumbBG: #6a6c75;
}
*::-webkit-scrollbar {
width: 11px;
}
* {
scrollbar-width: thin;
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
}
*::-webkit-scrollbar-track {
background: var(--scrollbarBG);
}
*::-webkit-scrollbar-thumb {
background-color: var(--thumbBG);
border-radius: 6px;
border: 3px solid var(--scrollbarBG);
}
html, html,
body { body {
margin: 0; margin: 0;
@ -15,7 +39,6 @@
<body> <body>
<group-transaction></group-transaction> <group-transaction></group-transaction>
<script src="group-transaction.js"></script> <script src="group-transaction.js"></script>
</body> </body>

View File

@ -39,7 +39,6 @@
<body> <body>
<group-management></group-management> <group-management></group-management>
<script src="group-management.js"></script> <script src="group-management.js"></script>
</body> </body>

File diff suppressed because one or more lines are too long

View File

@ -98,7 +98,7 @@ parentEpml.ready().then(() => {
menus: [], menus: [],
parent: false parent: false
}, },
{ {
url: 'puzzles', url: 'puzzles',
domain: 'core', domain: 'core',
page: 'puzzles/index.html', page: 'puzzles/index.html',
@ -106,7 +106,7 @@ parentEpml.ready().then(() => {
icon: 'extension', icon: 'extension',
menus: [], menus: [],
parent: false parent: false
} }
] ]
const registerPlugins = (pluginInfo) => { const registerPlugins = (pluginInfo) => {

View File

@ -3,7 +3,7 @@ import { LitElement, html, css } from 'lit'
class ChainMessaging extends LitElement { class ChainMessaging extends LitElement {
static get properties() { static get properties() {
return { return {
loading: { type: Boolean }, loading: { type: Boolean }
} }
} }
@ -30,13 +30,11 @@ class ChainMessaging extends LitElement {
constructor() { constructor() {
super() super()
// ...
} }
render() { render() {
return html` return html`
<div id="chain-messaging-page"> <div id="chain-messaging-page">
<h2 style="text-align: center; margin-top: 3rem;">Coming Soon!</h2> <h2 style="text-align: center; margin-top: 3rem;">Coming Soon!</h2>
</div> </div>
` `

View File

@ -28,6 +28,7 @@
border: 3px solid var(--scrollbarBG); border: 3px solid var(--scrollbarBG);
} }
html,
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
@ -38,7 +39,6 @@
<body> <body>
<q-messaging></q-messaging> <q-messaging></q-messaging>
<script src="messaging.js"></script> <script src="messaging.js"></script>
</body> </body>

View File

@ -40,7 +40,6 @@ class Messaging extends LitElement {
color: rgb(3, 169, 244); color: rgb(3, 169, 244);
margin-top: .5rem; margin-top: .5rem;
font-weight: 400; font-weight: 400;
/* font-size: 19px; */
text-align: center; text-align: center;
} }
@ -60,7 +59,6 @@ class Messaging extends LitElement {
.divCard { .divCard {
border: 1px solid #eee; border: 1px solid #eee;
padding: 1em; padding: 1em;
/** box-shadow: 0 1px 1px 0 rgba(0,0,0,0.14), 0 2px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20); **/
box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20); box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20);
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }

View File

@ -33,14 +33,13 @@
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background-color: #fff; background-color: #fff;
overflow: hidden;
} }
</style> </style>
</head> </head>
<body> <body>
<q-chat></q-chat> <q-chat></q-chat>
<script type="module" src="q-chat.js"></script> <script src="q-chat.js"></script>
</body> </body>
</html> </html>

View File

@ -2,13 +2,10 @@ import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { Epml } from '../../../../epml.js' import { Epml } from '../../../../epml.js'
// Components
import '../../components/ChatWelcomePage.js' import '../../components/ChatWelcomePage.js'
import '../../components/ChatHead.js' import '../../components/ChatHead.js'
import '../../components/ChatPage.js' import '../../components/ChatPage.js'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-dialog' import '@material/mwc-dialog'
@ -296,11 +293,10 @@ class Chat extends LitElement {
</div> </div>
<div class="chat"> <div class="chat">
<div id="newMessageBar" class="new-message-bar hide-new-message-bar clearfix" @click=${ () => this.scrollToBottom()}> <div id="newMessageBar" class="new-message-bar hide-new-message-bar clearfix" @click=${() => this.scrollToBottom()}>
<span style="flex: 1;">New Message</span> <span style="flex: 1;">New Message</span>
<span>(Click to scroll down) <mwc-icon style="font-size: 16px; vertical-align: bottom;">keyboard_arrow_down</mwc-icon></span> <span>(Click to scroll down) <mwc-icon style="font-size: 16px; vertical-align: bottom;">keyboard_arrow_down</mwc-icon></span>
</div> </div>
<div class="chat-history"> <div class="chat-history">
${window.parent.location.pathname !== "/app/q-chat" ? html`${this.renderChatPage(this.chatId)}` : html`${this.renderChatWelcomePage()}`} ${window.parent.location.pathname !== "/app/q-chat" ? html`${this.renderChatPage(this.chatId)}` : html`${this.renderChatWelcomePage()}`}
</div> </div>
@ -474,9 +470,7 @@ class Chat extends LitElement {
}) })
parentEpml.subscribe('chat_heads', chatHeads => { parentEpml.subscribe('chat_heads', chatHeads => {
chatHeads = JSON.parse(chatHeads) chatHeads = JSON.parse(chatHeads)
// setTimeout(() => {
this.getChatHeadFromState(chatHeads) this.getChatHeadFromState(chatHeads)
// }, 5000)
}) })
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}` url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}`

View File

@ -32,7 +32,7 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background: #fff; background-color: #fff;
} }
</style> </style>
</head> </head>

View File

@ -1,13 +1,13 @@
import { LitElement, html, css } from "lit"; import { LitElement, html, css } from 'lit'
import { render } from "lit/html.js"; import { render } from 'lit/html.js'
import { Epml } from "../../../epml.js"; import { Epml } from '../../../epml.js'
import "@material/mwc-icon"; import '@material/mwc-icon'
import "@material/mwc-button"; import '@material/mwc-button'
import "@material/mwc-dialog"; import '@material/mwc-dialog'
import "@material/mwc-textfield"; import '@material/mwc-textfield'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class MintingInfo extends LitElement { class MintingInfo extends LitElement {
static get properties() { static get properties() {
@ -18,7 +18,7 @@ class MintingInfo extends LitElement {
nodeInfo: { type: Array }, nodeInfo: { type: Array },
sampleBlock: { type: Array }, sampleBlock: { type: Array },
addressInfo: { type: Array }, addressInfo: { type: Array },
addressLevel: { type: Array }, addressLevel: { type: Array }
} }
} }
@ -195,8 +195,8 @@ class MintingInfo extends LitElement {
} }
render() { render() {
if (this.renderMintingPage() === "false") { if (this.renderMintingPage() === "false") {
return html` return html`
<div> <div>
<div> <div>
<span class="header-title">General Minting Details</span> <span class="header-title">General Minting Details</span>
@ -247,7 +247,7 @@ class MintingInfo extends LitElement {
</mwc-dialog> </mwc-dialog>
</div> </div>
`} else { `} else {
return html` return html`
<div> <div>
<div> <div>
<span class="header-title">General Minting Details</span> <span class="header-title">General Minting Details</span>
@ -356,14 +356,14 @@ class MintingInfo extends LitElement {
firstUpdated() { firstUpdated() {
const getAdminInfo = () => { const getAdminInfo = () => {
parentEpml.request("apiCall", {url: `/admin/info`}).then((res) => { parentEpml.request("apiCall", { url: `/admin/info` }).then((res) => {
setTimeout(() => {this.adminInfo = res;}, 1); setTimeout(() => { this.adminInfo = res; }, 1);
}); });
setTimeout(getAdminInfo, 30000); setTimeout(getAdminInfo, 30000);
}; };
const getNodeInfo = () => { const getNodeInfo = () => {
parentEpml.request("apiCall", {url: `/admin/status`}).then((res) => { parentEpml.request("apiCall", { url: `/admin/status` }).then((res) => {
this.nodeInfo = res; this.nodeInfo = res;
// Now look up the sample block // Now look up the sample block
getSampleBlock() getSampleBlock()
@ -373,21 +373,21 @@ class MintingInfo extends LitElement {
const getSampleBlock = () => { const getSampleBlock = () => {
let callBlock = parseFloat(this.nodeInfo.height) - 10000; let callBlock = parseFloat(this.nodeInfo.height) - 10000;
parentEpml.request("apiCall", {url: `/blocks/byheight/${callBlock}`}).then((res) => { parentEpml.request("apiCall", { url: `/blocks/byheight/${callBlock}` }).then((res) => {
setTimeout(() => {this.sampleBlock = res;}, 1); setTimeout(() => { this.sampleBlock = res; }, 1);
}); });
}; };
const getAddressInfo = () => { const getAddressInfo = () => {
parentEpml.request('apiCall', {url: `/addresses/${window.parent.reduxStore.getState().app.selectedAddress.address}`}).then((res) => { parentEpml.request('apiCall', { url: `/addresses/${window.parent.reduxStore.getState().app.selectedAddress.address}` }).then((res) => {
setTimeout(() => {this.addressInfo = res;}, 1); setTimeout(() => { this.addressInfo = res; }, 1);
}); });
setTimeout(getAddressInfo, 30000); setTimeout(getAddressInfo, 30000);
}; };
const getAddressLevel = () => { const getAddressLevel = () => {
parentEpml.request('apiCall', {url: `/addresses/online/levels`}).then((res) => { parentEpml.request('apiCall', { url: `/addresses/online/levels` }).then((res) => {
setTimeout(() => {this.addressLevel = res;}, 1); setTimeout(() => { this.addressLevel = res; }, 1);
}); });
setTimeout(getAddressLevel, 30000); setTimeout(getAddressLevel, 30000);
}; };
@ -432,30 +432,30 @@ class MintingInfo extends LitElement {
renderActivateHelp() { renderActivateHelp() {
if (this.renderMintingPage() === "false") { if (this.renderMintingPage() === "false") {
return html `Activate Account Details <div class="level-blue">==></div> Not Activated<br><mwc-button class="red-button" @click=${() => this.shadowRoot.querySelector("#activateAccountDialog").show()}><mwc-icon class="help-icon">help_outline</mwc-icon>&nbsp;Press For Help</mwc-button>`; return html`Activate Account Details <div class="level-blue">==></div> Not Activated<br><mwc-button class="red-button" @click=${() => this.shadowRoot.querySelector("#activateAccountDialog").show()}><mwc-icon class="help-icon">help_outline</mwc-icon>&nbsp;Press For Help</mwc-button>`;
} else { } else {
return "No Details"; return "No Details";
} }
} }
_averageBlockTime() { _averageBlockTime() {
let avgBlockString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString(); let avgBlockString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString();
let averageTimeString = ((avgBlockString / 1000) / 10000).toFixed(2); let averageTimeString = ((avgBlockString / 1000) / 10000).toFixed(2);
let averageBlockTimeString = (averageTimeString).toString(); let averageBlockTimeString = (averageTimeString).toString();
return "" + averageBlockTimeString; return "" + averageBlockTimeString;
} }
_timeCalc() { _timeCalc() {
let timeString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString(); let timeString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString();
let averageString = ((timeString / 1000) / 10000).toFixed(2); let averageString = ((timeString / 1000) / 10000).toFixed(2);
let averageBlockDay = (86400 / averageString).toFixed(2); let averageBlockDay = (86400 / averageString).toFixed(2);
let averageBlockDayString = (averageBlockDay).toString(); let averageBlockDayString = (averageBlockDay).toString();
return "" + averageBlockDayString; return "" + averageBlockDayString;
} }
_dayReward() { _dayReward() {
let rewardString = (this._timeCalc() * this._blockReward()).toFixed(2); let rewardString = (this._timeCalc() * this._blockReward()).toFixed(2);
let rewardDayString = (rewardString).toString(); let rewardDayString = (rewardString).toString();
return "" + rewardDayString ; return "" + rewardDayString;
} }
_mintingStatus() { _mintingStatus() {
@ -478,7 +478,7 @@ class MintingInfo extends LitElement {
renderMintingHelp() { renderMintingHelp() {
if (this._mintingStatus() === "Not Minting") { if (this._mintingStatus() === "Not Minting") {
return html `Minting Account Details <div class="level-blue">==></div> Not A Minter<br><mwc-button class="red-button" @click=${() => this.shadowRoot.querySelector("#becomeMinterDialog").show()}><mwc-icon class="help-icon">help_outline</mwc-icon>&nbsp;Press For Help</mwc-button>`; return html`Minting Account Details <div class="level-blue">==></div> Not A Minter<br><mwc-button class="red-button" @click=${() => this.shadowRoot.querySelector("#becomeMinterDialog").show()}><mwc-icon class="help-icon">help_outline</mwc-icon>&nbsp;Press For Help</mwc-button>`;
} else { } else {
return "Minting Account Details"; return "Minting Account Details";
} }

View File

@ -32,14 +32,14 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background: #fff; background-color: #fff;
} }
</style> </style>
</head> </head>
<body> <body>
<name-registration></name-registration> <name-registration></name-registration>
<script type="module" src="name-registration.js"></script> <script src="name-registration.js"></script>
</body> </body>
</html> </html>

View File

@ -6,10 +6,9 @@ import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-textfield' import '@material/mwc-textfield'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js' import '@vaadin/grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -86,7 +85,7 @@ class NameRegistration extends LitElement {
<div class="divCard"> <div class="divCard">
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Registered Names</h3> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Registered Names</h3>
<vaadin-grid id="namesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.names)}" aria-label="Names" .items="${this.names}" height-by-rows> <vaadin-grid theme="compact" id="namesGrid" ?hidden="${this.isEmptyArray(this.names)}" aria-label="Names" .items="${this.names}" all-rows-visible>
<vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => { <vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => {
render(html`${this.renderAvatar(data.item)}`, root) render(html`${this.renderAvatar(data.item)}`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
@ -216,18 +215,18 @@ class NameRegistration extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const url = `${nodeUrl}/transactions/unitfee?txType=REGISTER_NAME`; const url = `${nodeUrl}/transactions/unitfee?txType=REGISTER_NAME`;
await fetch(url) await fetch(url)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
return Promise.reject(response); return Promise.reject(response);
}) })
.then((json) => { .then((json) => {
this.fee = (Number(json) / 1e8).toFixed(8); this.fee = (Number(json) / 1e8).toFixed(8);
}) })
.catch((response) => { .catch((response) => {
console.log(response.status, response.statusText, 'Need Core Update'); console.log(response.status, response.statusText, 'Need Core Update');
}) })
} }
getApiKey() { getApiKey() {
@ -248,7 +247,7 @@ class NameRegistration extends LitElement {
const nameInput = this.shadowRoot.getElementById("nameInput").value const nameInput = this.shadowRoot.getElementById("nameInput").value
const descInput = this.shadowRoot.getElementById("descInput").value const descInput = this.shadowRoot.getElementById("descInput").value
// Check for valid...^ // Check for valid...
this.registerNameLoading = true this.registerNameLoading = true
// Get Last Ref // Get Last Ref

View File

@ -1,42 +1,42 @@
import { LitElement, html, css } from "lit"; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { Epml } from "../../../epml.js"; import { Epml } from '../../../epml.js'
import "@polymer/paper-spinner/paper-spinner-lite.js"; import '@polymer/paper-spinner/paper-spinner-lite.js'
import "@vaadin/vaadin-grid/vaadin-grid.js"; import '@material/mwc-icon'
import "@vaadin/vaadin-grid/theme/material/all-imports.js"; import '@material/mwc-textfield'
import "@material/mwc-icon"; import '@material/mwc-button'
import "@material/mwc-textfield"; import '@material/mwc-dialog'
import "@material/mwc-button"; import '@vaadin/grid/vaadin-grid.js'
import "@material/mwc-dialog"; import '@vaadin/grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); const parentEpml = new Epml({ type: "WINDOW", source: window.parent })
class NodeManagement extends LitElement { class NodeManagement extends LitElement {
static get properties() { static get properties() {
return { return {
loading: { type: Boolean }, loading: { type: Boolean },
upTime: { type: String }, upTime: { type: String },
mintingAccounts: { type: Array }, mintingAccounts: { type: Array },
peers: { type: Array }, peers: { type: Array },
addMintingAccountLoading: { type: Boolean }, addMintingAccountLoading: { type: Boolean },
removeMintingAccountLoading: { type: Boolean }, removeMintingAccountLoading: { type: Boolean },
addPeerLoading: { type: Boolean }, addPeerLoading: { type: Boolean },
confPeerLoading: { type: Boolean }, confPeerLoading: { type: Boolean },
addMintingAccountKey: { type: String }, addMintingAccountKey: { type: String },
removeMintingAccountKey: { type: String }, removeMintingAccountKey: { type: String },
addPeerMessage: { type: String }, addPeerMessage: { type: String },
confPeerMessage: { type: String }, confPeerMessage: { type: String },
addMintingAccountMessage: { type: String }, addMintingAccountMessage: { type: String },
removeMintingAccountMessage: { type: String }, removeMintingAccountMessage: { type: String },
tempMintingAccount: { type: Object }, tempMintingAccount: { type: Object },
nodeConfig: { type: Object }, nodeConfig: { type: Object },
nodeDomain: { type: String }, nodeDomain: { type: String }
}; };
} }
static get styles() { static get styles() {
return css` return css`
* { * {
--mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-primary: rgb(3, 169, 244);
--paper-input-container-focus-color: var(--mdc-theme-primary); --paper-input-container-focus-color: var(--mdc-theme-primary);
@ -72,7 +72,6 @@ class NodeManagement extends LitElement {
} }
.node-card { .node-card {
/* margin:12px; */
padding: 12px 24px; padding: 12px 24px;
background: #fff; background: #fff;
border-radius: 2px; border-radius: 2px;
@ -95,38 +94,39 @@ class NodeManagement extends LitElement {
display: hidden !important; display: hidden !important;
visibility: none !important; visibility: none !important;
} }
.details { .details {
display: flex; display: flex;
font-size: 18px; font-size: 18px;
} }
`; `;
} }
constructor() { constructor() {
super(); super();
this.upTime = ""; this.upTime = "";
this.mintingAccounts = []; this.mintingAccounts = [];
this.peers = []; this.peers = [];
this.addPeerLoading = false; this.addPeerLoading = false;
this.confPeerLoading = false; this.confPeerLoading = false;
this.addMintingAccountLoading = false; this.addMintingAccountLoading = false;
this.removeMintingAccountLoading = false; this.removeMintingAccountLoading = false;
this.addMintingAccountKey = ""; this.addMintingAccountKey = "";
this.addPeerMessage = ""; this.addPeerMessage = "";
this.confPeerMessage = ""; this.confPeerMessage = "";
this.addMintingAccountMessage = ""; this.addMintingAccountMessage = "";
this.tempMintingAccount = {}; this.tempMintingAccount = {};
this.config = { this.config = {
user: { user: {
node: {}, node: {},
}, },
}; };
this.nodeConfig = {}; this.nodeConfig = {};
this.nodeDomain = ""; this.nodeDomain = "";
} }
render() { render() {
return html` return html`
<div id="node-management-page"> <div id="node-management-page">
<div class="node-card"> <div class="node-card">
<h2>Node management for: ${this.nodeDomain}</h2> <h2>Node management for: ${this.nodeDomain}</h2>
@ -143,7 +143,7 @@ class NodeManagement extends LitElement {
<mwc-button <mwc-button
style="float:right;" style="float:right;"
@click=${() => @click=${() =>
this.shadowRoot this.shadowRoot
.querySelector("#addMintingAccountDialog") .querySelector("#addMintingAccountDialog")
.show()} .show()}
><mwc-icon>add</mwc-icon>Add minting account</mwc-button ><mwc-icon>add</mwc-icon>Add minting account</mwc-button
@ -201,7 +201,7 @@ class NodeManagement extends LitElement {
</mwc-button> </mwc-button>
</mwc-dialog> </mwc-dialog>
<vaadin-grid id="mintingAccountsGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.mintingAccounts)}" aria-label="Minting Accounts" .items="${this.mintingAccounts}" height-by-rows> <vaadin-grid theme="compact" id="mintingAccountsGrid" ?hidden="${this.isEmptyArray(this.mintingAccounts)}" .items="${this.mintingAccounts}" aria-label="Minting Accounts" all-rows-visible>
<vaadin-grid-column auto-width header="Minting Account" path="mintingAccount"></vaadin-grid-column> <vaadin-grid-column auto-width header="Minting Account" path="mintingAccount"></vaadin-grid-column>
<vaadin-grid-column auto-width header="Recipient Account" path="recipientAccount"></vaadin-grid-column> <vaadin-grid-column auto-width header="Recipient Account" path="recipientAccount"></vaadin-grid-column>
<vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => { <vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => {
@ -253,12 +253,12 @@ class NodeManagement extends LitElement {
</mwc-button> </mwc-button>
</mwc-dialog> </mwc-dialog>
<vaadin-grid id="peersGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.peers)}" aria-label="Peers" .items="${this.peers}" height-by-rows> <vaadin-grid theme="compact" id="peersGrid" ?hidden="${this.isEmptyArray(this.peers)}" .items="${this.peers}" aria-label="Peers" all-rows-visible>
<vaadin-grid-column path="address"></vaadin-grid-column> <vaadin-grid-column path="address"></vaadin-grid-column>
<vaadin-grid-column path="lastHeight"></vaadin-grid-column> <vaadin-grid-column path="lastHeight"></vaadin-grid-column>
<vaadin-grid-column path="version" header="Build Version"></vaadin-grid-column> <vaadin-grid-column path="version" header="Build Version"></vaadin-grid-column>
<vaadin-grid-column path="age" header="Connected for"></vaadin-grid-column> <vaadin-grid-column path="age" header="Connected for"></vaadin-grid-column>
<vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => { <vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => {
render(html`<mwc-button class="red" @click=${() => this.removePeer(data.item.address, data.index)}><mwc-icon>delete</mwc-icon>Remove</mwc-button><mwc-button class="green" @click=${() => this.forceSyncPeer(data.item.address, data.index)}>Force Sync</mwc-button>`, root) render(html`<mwc-button class="red" @click=${() => this.removePeer(data.item.address, data.index)}><mwc-icon>delete</mwc-icon>Remove</mwc-button><mwc-button class="green" @click=${() => this.forceSyncPeer(data.item.address, data.index)}>Force Sync</mwc-button>`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
</vaadin-grid> </vaadin-grid>
@ -269,81 +269,81 @@ class NodeManagement extends LitElement {
</div> </div>
</div> </div>
`; `;
} }
forceSyncPeer (peerAddress, rowIndex) { forceSyncPeer(peerAddress, rowIndex) {
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
url: `/admin/forcesync?apiKey=${this.getApiKey()}`, url: `/admin/forcesync?apiKey=${this.getApiKey()}`,
method: "POST", method: "POST",
body: peerAddress, body: peerAddress,
}) })
.then((res) => { .then((res) => {
parentEpml.request('showSnackBar', "Starting Sync with Peer: " + peerAddress ); parentEpml.request('showSnackBar', "Starting Sync with Peer: " + peerAddress);
}); });
} }
removePeer(peerAddress, rowIndex) { removePeer(peerAddress, rowIndex) {
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
url: `/peers?apiKey=${this.getApiKey()}`, url: `/peers?apiKey=${this.getApiKey()}`,
method: "DELETE", method: "DELETE",
body: peerAddress, body: peerAddress,
}) })
.then((res) => { .then((res) => {
parentEpml.request('showSnackBar', "Successfully removed Peer: " + peerAddress ); parentEpml.request('showSnackBar', "Successfully removed Peer: " + peerAddress);
this.peers.splice(rowIndex, 1); this.peers.splice(rowIndex, 1);
}); });
} }
onPageNavigation(pageUrl) { onPageNavigation(pageUrl) {
parentEpml.request("setPageUrl", pageUrl); parentEpml.request("setPageUrl", pageUrl);
} }
addPeer(e) { addPeer(e) {
this.addPeerLoading = true; this.addPeerLoading = true;
const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress") const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress")
.value; .value;
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
url: `/peers?apiKey=${this.getApiKey()}`, url: `/peers?apiKey=${this.getApiKey()}`,
method: "POST", method: "POST",
body: addPeerAddress, body: addPeerAddress,
}) })
.then((res) => { .then((res) => {
this.addPeerMessage = res.message; this.addPeerMessage = res.message;
this.addPeerLoading = false; this.addPeerLoading = false;
}); });
} }
addMintingAccount(e) { addMintingAccount(e) {
this.addMintingAccountLoading = true; this.addMintingAccountLoading = true;
this.addMintingAccountMessage = "Loading..."; this.addMintingAccountMessage = "Loading...";
this.addMintingAccountKey = this.shadowRoot.querySelector( this.addMintingAccountKey = this.shadowRoot.querySelector(
"#addMintingAccountKey" "#addMintingAccountKey"
).value; ).value;
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`, url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`,
method: "POST", method: "POST",
body: this.addMintingAccountKey, body: this.addMintingAccountKey,
}) })
.then((res) => { .then((res) => {
if (res === true) { if (res === true) {
this.updateMintingAccounts(); this.updateMintingAccounts();
this.addMintingAccountKey = ""; this.addMintingAccountKey = "";
this.addMintingAccountMessage = "Minting Node Added Successfully!"; this.addMintingAccountMessage = "Minting Node Added Successfully!";
this.addMintingAccountLoading = false; this.addMintingAccountLoading = false;
} else { } else {
this.addMintingAccountKey = ""; this.addMintingAccountKey = "";
this.addMintingAccountMessage = "Failed to Add Minting Node!"; // Corrected an error here thanks to crow (-_-) this.addMintingAccountMessage = "Failed to Add Minting Node!"; // Corrected an error here thanks to crow (-_-)
this.addMintingAccountLoading = false; this.addMintingAccountLoading = false;
} }
}); });
} }
updateMintingAccounts() { updateMintingAccounts() {
parentEpml.request("apiCall", { parentEpml.request("apiCall", {
@ -358,9 +358,9 @@ class NodeManagement extends LitElement {
const getSelectedText = () => { const getSelectedText = () => {
var text = ""; var text = "";
if (typeof window.getSelection != "undefined") { if (typeof window.getSelection != "undefined") {
text = window.getSelection().toString(); text = window.getSelection().toString();
} else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") {
text = this.shadowRoot.selection.createRange().text; text = this.shadowRoot.selection.createRange().text;
} }
return text; return text;
} }
@ -369,18 +369,18 @@ class NodeManagement extends LitElement {
let selectedText = getSelectedText(); let selectedText = getSelectedText();
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject) parentEpml.request('openCopyTextMenu', textMenuObject)
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
} }
removeMintingAccount(publicKey) { removeMintingAccount(publicKey) {
this.removeMintingAccountLoading = true; this.removeMintingAccountLoading = true;
parentEpml.request("apiCall", { parentEpml.request("apiCall", {
@ -397,116 +397,116 @@ class NodeManagement extends LitElement {
parentEpml.request('showSnackBar', "Failed to Remove Minting Account!"); parentEpml.request('showSnackBar', "Failed to Remove Minting Account!");
} }
}); });
}
firstUpdated() {
// Call updateMintingAccounts
this.updateMintingAccounts();
window.addEventListener("contextmenu", (event) => {
event.preventDefault();
this._textMenu(event)
});
window.addEventListener("click", () => {
parentEpml.request('closeCopyTextMenu', null)
});
window.onkeyup = (e) => {
if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null)
} }
// Calculate HH MM SS from Milliseconds... firstUpdated() {
const convertMsToTime = (milliseconds) => {
let day, hour, minute, seconds;
seconds = Math.floor(milliseconds / 1000);
minute = Math.floor(seconds / 60);
seconds = seconds % 60;
hour = Math.floor(minute / 60);
minute = minute % 60;
day = Math.floor(hour / 24);
hour = hour % 24;
if (isNaN(day)) {
return "offline";
}
return day + "d " + hour + "h " + minute + "m";
};
const getNodeUpTime = () => { // Call updateMintingAccounts
parentEpml this.updateMintingAccounts();
.request("apiCall", {
url: `/admin/uptime`, window.addEventListener("contextmenu", (event) => {
}) event.preventDefault();
.then((res) => { this._textMenu(event)
this.upTime = "";
setTimeout(() => {
this.upTime = convertMsToTime(res);
}, 1);
}); });
window.addEventListener("click", () => {
setTimeout(getNodeUpTime, this.config.user.nodeSettings.pingInterval); parentEpml.request('closeCopyTextMenu', null)
};
const updatePeers = () => {
parentEpml
.request("apiCall", {
url: `/peers`,
})
.then((res) => {
setTimeout(() => {
this.peers = res;
}, 1);
}); });
window.onkeyup = (e) => {
setTimeout(updatePeers, this.config.user.nodeSettings.pingInterval); if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null)
};
const getNodeConfig = () => {
parentEpml.request("getNodeConfig").then((res) => {
setTimeout(() => {
this.nodeConfig = res;
}, 1);
let myNode = window.parent.reduxStore.getState().app.nodeConfig
.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
this.nodeDomain = myNode.domain + ":" + myNode.port;
});
setTimeout(getNodeConfig, 1000);
};
let configLoaded = false;
parentEpml.ready().then(() => {
parentEpml.subscribe("config", async c => {
if (!configLoaded) {
setTimeout(getNodeUpTime, 1);
setTimeout(updatePeers, 1);
setTimeout(this.updateMintingAccounts, 1);
setTimeout(getNodeConfig, 1);
configLoaded = true;
} }
this.config = JSON.parse(c);
})
parentEpml.subscribe('copy_menu_switch', async value => {
if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection();
})
});
parentEpml.imReady();
}
getApiKey() { // Calculate HH MM SS from Milliseconds...
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const convertMsToTime = (milliseconds) => {
let apiKey = myNode.apiKey; let day, hour, minute, seconds;
return apiKey; seconds = Math.floor(milliseconds / 1000);
} minute = Math.floor(seconds / 60);
seconds = seconds % 60;
hour = Math.floor(minute / 60);
minute = minute % 60;
day = Math.floor(hour / 24);
hour = hour % 24;
if (isNaN(day)) {
return "offline";
}
return day + "d " + hour + "h " + minute + "m";
};
clearSelection() { const getNodeUpTime = () => {
window.getSelection().removeAllRanges() parentEpml
window.parent.getSelection().removeAllRanges() .request("apiCall", {
} url: `/admin/uptime`,
})
.then((res) => {
this.upTime = "";
setTimeout(() => {
this.upTime = convertMsToTime(res);
}, 1);
});
isEmptyArray(arr) { setTimeout(getNodeUpTime, this.config.user.nodeSettings.pingInterval);
if (!arr) return true; };
return arr.length === 0;
} const updatePeers = () => {
parentEpml
.request("apiCall", {
url: `/peers`,
})
.then((res) => {
setTimeout(() => {
this.peers = res;
}, 1);
});
setTimeout(updatePeers, this.config.user.nodeSettings.pingInterval);
};
const getNodeConfig = () => {
parentEpml.request("getNodeConfig").then((res) => {
setTimeout(() => {
this.nodeConfig = res;
}, 1);
let myNode = window.parent.reduxStore.getState().app.nodeConfig
.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
this.nodeDomain = myNode.domain + ":" + myNode.port;
});
setTimeout(getNodeConfig, 1000);
};
let configLoaded = false;
parentEpml.ready().then(() => {
parentEpml.subscribe("config", async c => {
if (!configLoaded) {
setTimeout(getNodeUpTime, 1);
setTimeout(updatePeers, 1);
setTimeout(this.updateMintingAccounts, 1);
setTimeout(getNodeConfig, 1);
configLoaded = true;
}
this.config = JSON.parse(c);
})
parentEpml.subscribe('copy_menu_switch', async value => {
if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection();
})
});
parentEpml.imReady();
}
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey;
return apiKey;
}
clearSelection() {
window.getSelection().removeAllRanges()
window.parent.getSelection().removeAllRanges()
}
isEmptyArray(arr) {
if (!arr) return true;
return arr.length === 0;
}
} }
window.customElements.define("node-management", NodeManagement); window.customElements.define("node-management", NodeManagement);

View File

@ -32,14 +32,14 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background: #fff; background-color: #fff;
} }
</style> </style>
</head> </head>
<body> <body>
<puzzles-info></puzzles-info> <puzzles-info></puzzles-info>
<script type="module" src="puzzles.js"></script> <script src="puzzles.js"></script>
</body> </body>
</html> </html>

View File

@ -6,37 +6,36 @@ import { Epml } from '../../../epml.js'
import nacl from '../../../../qortal-ui-crypto/api/deps/nacl-fast.js' import nacl from '../../../../qortal-ui-crypto/api/deps/nacl-fast.js'
import Base58 from '../../../../qortal-ui-crypto/api/deps/Base58.js' import Base58 from '../../../../qortal-ui-crypto/api/deps/Base58.js'
import publicKeyToAddress from '../../../../qortal-ui-crypto/api/wallet/publicKeyToAddress.js' import publicKeyToAddress from '../../../../qortal-ui-crypto/api/wallet/publicKeyToAddress.js'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-textfield' import '@material/mwc-textfield'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@material/mwc-slider' import '@material/mwc-slider'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js' import '@vaadin/grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const DEFAULT_FEE = 0.001 const DEFAULT_FEE = 0.001
const PAYMENT_TX_TYPE = 2 const PAYMENT_TX_TYPE = 2
class Puzzles extends LitElement { class Puzzles extends LitElement {
static get properties() { static get properties() {
return { return {
loading: { type: Boolean }, loading: { type: Boolean },
invalid: { type: Boolean }, invalid: { type: Boolean },
puzzles: { type: Array }, puzzles: { type: Array },
solved: { type: Object }, solved: { type: Object },
selectedAddress: { type: Object }, selectedAddress: { type: Object },
selectedPuzzle: { type: Object }, selectedPuzzle: { type: Object },
error: { type: Boolean }, error: { type: Boolean },
message: { type: String } message: { type: String }
} }
} }
static get styles() { static get styles() {
return css` return css`
* { * {
--mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary); --mdc-theme-secondary: var(--mdc-theme-primary);
@ -65,48 +64,48 @@ class Puzzles extends LitElement {
font-size: smaller; font-size: smaller;
} }
` `
} }
constructor() { constructor() {
super() super()
this.loading = false this.loading = false
this.invalid = true this.invalid = true
this.puzzles = [] this.puzzles = []
this.solved = {} this.solved = {}
this.selectedAddress = {} this.selectedAddress = {}
this.selectedPuzzle = {} this.selectedPuzzle = {}
this.error = false this.error = false
this.message = '' this.message = ''
} }
render() { render() {
return html` return html`
<div id="puzzle-page"> <div id="puzzle-page">
<div style="min-height:48px; display: flex; padding-bottom: 6px;"> <div style="min-height:48px; display: flex; padding-bottom: 6px;">
<h3 style="margin: 0; flex: 1; padding-top: 8px; display: inline;">Puzzles</h3> <h3 style="margin: 0; flex: 1; padding-top: 8px; display: inline;">Puzzles</h3>
</div> </div>
<div class="divCard">
<vaadin-grid id="puzzlesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.puzzles)}" .items="${this.puzzles}" height-by-rows> <vaadin-grid theme="compact" id="puzzlesGrid" ?hidden="${this.isEmptyArray(this.puzzles)}" .items="${this.puzzles}" aria-label="Puzzles" all-rows-visible>
<vaadin-grid-column auto-width header="Reward" .renderer=${(root, column, data) => { <vaadin-grid-column auto-width header="Reward" .renderer=${(root, column, data) => {
if (data.item.isSolved) { if (data.item.isSolved) {
render(html`<span style="font-size: smaller;">SOLVED by ${data.item.winner}</span>`, root) render(html`<span style="font-size: smaller;">SOLVED by ${data.item.winner}</span>`, root)
} else { } else {
render(html`<span>${data.item.reward} QORT</span>`, root) render(html`<span>${data.item.reward} QORT</span>`, root)
} }
}}></vaadin-grid-column> }}></vaadin-grid-column>
<vaadin-grid-column auto-width path="name"></vaadin-grid-column> <vaadin-grid-column auto-width path="name"></vaadin-grid-column>
<vaadin-grid-column auto-width path="description"></vaadin-grid-column> <vaadin-grid-column auto-width path="description"></vaadin-grid-column>
<vaadin-grid-column auto-width path="clue" style="font-family: monospace; font-size: smaller;"></vaadin-grid-column> <vaadin-grid-column auto-width path="clue" style="font-family: monospace; font-size: smaller;"></vaadin-grid-column>
<vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => { <vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => {
if (data.item.isSolved) { if (data.item.isSolved) {
render(html``, root) render(html``, root)
} else { } else {
render(html`<mwc-button @click=${() => this.guessPuzzle(data.item)}><mwc-icon>queue</mwc-icon>Guess</mwc-button>`, root) render(html`<mwc-button @click=${() => this.guessPuzzle(data.item)}><mwc-icon>queue</mwc-icon>Guess</mwc-button>`, root)
} }
}}></vaadin-grid-column> }}></vaadin-grid-column>
</vaadin-grid> </vaadin-grid>
<mwc-dialog id="puzzleGuessDialog" scrimClickAction="${this.loading ? '' : 'close'}"> <mwc-dialog id="puzzleGuessDialog" scrimClickAction="${this.loading ? '' : 'close'}">
<div>Enter your guess to solve this puzzle and win ${this.selectedPuzzle.reward} QORT:</div> <div>Enter your guess to solve this puzzle and win ${this.selectedPuzzle.reward} QORT:</div>
<br> <br>
<div id="puzzleGuessName">Name: ${this.selectedPuzzle.name}</div> <div id="puzzleGuessName">Name: ${this.selectedPuzzle.name}</div>
@ -122,7 +121,8 @@ class Puzzles extends LitElement {
<paper-spinner-lite <paper-spinner-lite
style="margin-top:12px;" style="margin-top:12px;"
?active="${this.loading}" ?active="${this.loading}"
alt="Claiming puzzle reward"></paper-spinner-lite> alt="Claiming puzzle reward">
</paper-spinner-lite>
</span> </span>
<span ?hidden=${this.message === ''} style="${this.error ? 'color:red;' : ''}"> <span ?hidden=${this.message === ''} style="${this.error ? 'color:red;' : ''}">
${this.message} ${this.message}
@ -145,317 +145,317 @@ class Puzzles extends LitElement {
</mwc-dialog> </mwc-dialog>
</div> </div>
` `
} }
firstUpdated() { firstUpdated() {
window.addEventListener("contextmenu", (event) => { window.addEventListener("contextmenu", (event) => {
event.preventDefault(); event.preventDefault();
this._textMenu(event) this._textMenu(event)
}); });
window.addEventListener("click", () => { window.addEventListener("click", () => {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
}); });
window.onkeyup = (e) => { window.onkeyup = (e) => {
if (e.keyCode === 27) { if (e.keyCode === 27) {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
} }
} }
const textBox = this.shadowRoot.getElementById("puzzleGuess") const textBox = this.shadowRoot.getElementById("puzzleGuess")
// keep track of input validity so we can enabled/disable submit button // keep track of input validity so we can enabled/disable submit button
textBox.validityTransform = (newValue, nativeValidity) => { textBox.validityTransform = (newValue, nativeValidity) => {
this.invalid = !nativeValidity.valid this.invalid = !nativeValidity.valid
return nativeValidity return nativeValidity
} }
const getPuzzleGroupMembers = async () => { const getPuzzleGroupMembers = async () => {
return await parentEpml.request('apiCall', { return await parentEpml.request('apiCall', {
url: `/groups/members/165` url: `/groups/members/165`
}) })
} }
const getBalance = async(address) => { const getBalance = async (address) => {
return await parentEpml.request('apiCall', { return await parentEpml.request('apiCall', {
url: `/addresses/balance/${address}` url: `/addresses/balance/${address}`
}) })
} }
const getName = async(memberAddress) => { const getName = async (memberAddress) => {
let _names = await parentEpml.request('apiCall', { let _names = await parentEpml.request('apiCall', {
url: `/names/address/${memberAddress}` url: `/names/address/${memberAddress}`
}) })
if (_names.length === 0) return ""; if (_names.length === 0) return "";
return _names[0].name return _names[0].name
} }
const getNameInfo = async(name) => { const getNameInfo = async (name) => {
// We have to explicitly encode '#' to stop them being interpreted as in-page references // We have to explicitly encode '#' to stop them being interpreted as in-page references
name = name.replaceAll('#', '%23') name = name.replaceAll('#', '%23')
return await parentEpml.request('apiCall', { return await parentEpml.request('apiCall', {
url: `/names/${name}` url: `/names/${name}`
}) })
} }
const getFirstOutgoingPayment = async(sender) => { const getFirstOutgoingPayment = async (sender) => {
let _payments = await parentEpml.request('apiCall', { let _payments = await parentEpml.request('apiCall', {
url: `/transactions/search?confirmationStatus=CONFIRMED&limit=20&txType=PAYMENT&address=${sender}` url: `/transactions/search?confirmationStatus=CONFIRMED&limit=20&txType=PAYMENT&address=${sender}`
}) })
return _payments.find(payment => payment.creatorAddress === sender) return _payments.find(payment => payment.creatorAddress === sender)
} }
const updatePuzzles = async () => { const updatePuzzles = async () => {
let _puzzleGroupMembers = await getPuzzleGroupMembers() let _puzzleGroupMembers = await getPuzzleGroupMembers()
let _puzzles = [] let _puzzles = []
await Promise.all(_puzzleGroupMembers.members await Promise.all(_puzzleGroupMembers.members
.sort((a, b) => b.joined - a.joined) .sort((a, b) => b.joined - a.joined)
.map(async (member) => { .map(async (member) => {
let _puzzleAddress = member.member let _puzzleAddress = member.member
if (member.isAdmin) return if (member.isAdmin) return
// Already solved? No need to refresh info // Already solved? No need to refresh info
if (this.solved[_puzzleAddress]) { if (this.solved[_puzzleAddress]) {
_puzzles.push(this.solved[_puzzleAddress]) _puzzles.push(this.solved[_puzzleAddress])
return return
} }
let _name = await getName(_puzzleAddress) let _name = await getName(_puzzleAddress)
// No name??? // No name???
if (_name === "") return if (_name === "") return
let _reward = await getBalance(_puzzleAddress) let _reward = await getBalance(_puzzleAddress)
let _isSolved = _reward < 1.0; let _isSolved = _reward < 1.0;
let _nameInfo = await getNameInfo(_name) let _nameInfo = await getNameInfo(_name)
let _nameData = JSON.parse(_nameInfo.data) let _nameData = JSON.parse(_nameInfo.data)
let _puzzle = { let _puzzle = {
reward: _reward, reward: _reward,
address: _puzzleAddress, address: _puzzleAddress,
name: _name, name: _name,
description: _nameData.description, description: _nameData.description,
isSolved: _isSolved isSolved: _isSolved
} }
if (!_isSolved && _nameData.clue) if (!_isSolved && _nameData.clue)
_puzzle.clue = _nameData.clue; _puzzle.clue = _nameData.clue;
if (_isSolved) { if (_isSolved) {
// Info on winner // Info on winner
let _payment = await getFirstOutgoingPayment(_puzzleAddress) let _payment = await getFirstOutgoingPayment(_puzzleAddress)
_puzzle.winner = _payment.recipient _puzzle.winner = _payment.recipient
// Does winner have a name? // Does winner have a name?
let _winnerName = await getName(_puzzle.winner) let _winnerName = await getName(_puzzle.winner)
if (_winnerName) _puzzle.winner = _winnerName if (_winnerName) _puzzle.winner = _winnerName
// Add to 'solved' map to prevent info refresh as it'll never change // Add to 'solved' map to prevent info refresh as it'll never change
this.solved[_puzzleAddress] = _puzzle this.solved[_puzzleAddress] = _puzzle
} }
_puzzles.push(_puzzle); _puzzles.push(_puzzle);
})) }))
this.puzzles = _puzzles; this.puzzles = _puzzles;
setTimeout(updatePuzzles, 20000) setTimeout(updatePuzzles, 20000)
} }
let configLoaded = false let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {} this.selectedAddress = {}
selectedAddress = JSON.parse(selectedAddress) selectedAddress = JSON.parse(selectedAddress)
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
this.selectedAddress = selectedAddress this.selectedAddress = selectedAddress
}) })
parentEpml.subscribe('config', c => { parentEpml.subscribe('config', c => {
if (!configLoaded) { if (!configLoaded) {
setTimeout(updatePuzzles, 1) setTimeout(updatePuzzles, 1)
configLoaded = true configLoaded = true
} }
this.config = JSON.parse(c) this.config = JSON.parse(c)
}) })
parentEpml.subscribe('copy_menu_switch', async value => { parentEpml.subscribe('copy_menu_switch', async value => {
if (value === 'false' && window.getSelection().toString().length !== 0) { if (value === 'false' && window.getSelection().toString().length !== 0) {
this.clearSelection() this.clearSelection()
} }
}) })
parentEpml.subscribe('frame_paste_menu_switch', async res => { parentEpml.subscribe('frame_paste_menu_switch', async res => {
res = JSON.parse(res) res = JSON.parse(res)
if (res.isOpen === false && this.isPasteMenuOpen === true) { if (res.isOpen === false && this.isPasteMenuOpen === true) {
this.pasteToTextBox(textBox) this.pasteToTextBox(textBox)
this.isPasteMenuOpen = false this.isPasteMenuOpen = false
} }
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
textBox.addEventListener('contextmenu', (event) => { textBox.addEventListener('contextmenu', (event) => {
const getSelectedText = () => { const getSelectedText = () => {
var text = ""; var text = "";
if (typeof window.getSelection != "undefined") { if (typeof window.getSelection != "undefined") {
text = window.getSelection().toString(); text = window.getSelection().toString();
} else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") {
text = this.shadowRoot.selection.createRange().text; text = this.shadowRoot.selection.createRange().text;
} }
return text; return text;
} }
const checkSelectedTextAndShowMenu = () => { const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText(); let selectedText = getSelectedText();
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
// ... // ...
} else { } else {
this.pasteMenu(event) this.pasteMenu(event)
this.isPasteMenuOpen = true this.isPasteMenuOpen = true
// Prevent Default and Stop Event Bubbling // Prevent Default and Stop Event Bubbling
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
}) })
} }
async guessPuzzle(puzzle) { async guessPuzzle(puzzle) {
this.selectedPuzzle = puzzle this.selectedPuzzle = puzzle
this.shadowRoot.getElementById("puzzleGuess").value = '' this.shadowRoot.getElementById("puzzleGuess").value = ''
this.shadowRoot.getElementById("puzzleGuess").checkValidity() this.shadowRoot.getElementById("puzzleGuess").checkValidity()
this.message = '' this.message = ''
this.invalid = true this.invalid = true
this.shadowRoot.querySelector('#puzzleGuessDialog').show() this.shadowRoot.querySelector('#puzzleGuessDialog').show()
} }
async submitPuzzleGuess(e) { async submitPuzzleGuess(e) {
this.loading = true this.loading = true
this.error = false this.error = false
// Check for valid guess // Check for valid guess
const guess = this.shadowRoot.getElementById("puzzleGuess").value const guess = this.shadowRoot.getElementById("puzzleGuess").value
let _rawGuess = Base58.decode(guess) let _rawGuess = Base58.decode(guess)
let _keyPair = nacl.sign.keyPair.fromSeed(_rawGuess) let _keyPair = nacl.sign.keyPair.fromSeed(_rawGuess)
let _guessAddress = publicKeyToAddress(_keyPair.publicKey) let _guessAddress = publicKeyToAddress(_keyPair.publicKey)
console.log("Guess '" + _guessAddress + "' vs puzzle's address '" + this.selectedPuzzle.address + "'") console.log("Guess '" + _guessAddress + "' vs puzzle's address '" + this.selectedPuzzle.address + "'")
if (_guessAddress !== this.selectedPuzzle.address) { if (_guessAddress !== this.selectedPuzzle.address) {
this.error = true this.error = true
this.message = 'Guess incorrect!' this.message = 'Guess incorrect!'
this.loading = false this.loading = false
return return
} }
// Get Last Ref // Get Last Ref
const getLastRef = async (address) => { const getLastRef = async (address) => {
let myRef = await parentEpml.request('apiCall', { let myRef = await parentEpml.request('apiCall', {
url: `/addresses/lastreference/${address}` url: `/addresses/lastreference/${address}`
}) })
return myRef return myRef
} }
let lastRef = await getLastRef(_guessAddress) let lastRef = await getLastRef(_guessAddress)
let amount = this.selectedPuzzle.reward - DEFAULT_FEE; let amount = this.selectedPuzzle.reward - DEFAULT_FEE;
let recipientAddress = this.selectedAddress.address let recipientAddress = this.selectedAddress.address
let txnParams = { let txnParams = {
recipient: recipientAddress, recipient: recipientAddress,
amount: amount, amount: amount,
lastReference: lastRef, lastReference: lastRef,
fee: DEFAULT_FEE fee: DEFAULT_FEE
} }
// Mostly copied from qortal-ui-core/src/plugins/routes.js // Mostly copied from qortal-ui-core/src/plugins/routes.js
let txnResponse = await parentEpml.request('standaloneTransaction', { let txnResponse = await parentEpml.request('standaloneTransaction', {
type: 2, type: 2,
keyPair: { keyPair: {
publicKey: _keyPair.publicKey, publicKey: _keyPair.publicKey,
privateKey: _keyPair.secretKey privateKey: _keyPair.secretKey
}, },
params: txnParams params: txnParams
}) })
if (txnResponse.success) { if (txnResponse.success) {
this.message = 'Reward claim submitted - check wallet for reward!' this.message = 'Reward claim submitted - check wallet for reward!'
} else { } else {
this.error = true this.error = true
if (txnResponse.data) { if (txnResponse.data) {
this.message = "Error while claiming reward: " + txnResponse.data.message this.message = "Error while claiming reward: " + txnResponse.data.message
} else { } else {
this.message = "Error while claiming reward: " + txnResponse.message this.message = "Error while claiming reward: " + txnResponse.message
} }
} }
this.loading = false this.loading = false
} }
pasteToTextBox(textBox) { pasteToTextBox(textBox) {
// Return focus to the window // Return focus to the window
window.focus() window.focus()
navigator.clipboard.readText().then(clipboardText => { navigator.clipboard.readText().then(clipboardText => {
textBox.value += clipboardText textBox.value += clipboardText
textBox.focus() textBox.focus()
}); });
} }
pasteMenu(event) { pasteMenu(event) {
let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
parentEpml.request('openFramePasteMenu', eventObject) parentEpml.request('openFramePasteMenu', eventObject)
} }
_textMenu(event) { _textMenu(event) {
const getSelectedText = () => { const getSelectedText = () => {
var text = ""; var text = "";
if (typeof window.getSelection != "undefined") { if (typeof window.getSelection != "undefined") {
text = window.getSelection().toString(); text = window.getSelection().toString();
} else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") {
text = this.shadowRoot.selection.createRange().text; text = this.shadowRoot.selection.createRange().text;
} }
return text; return text;
} }
const checkSelectedTextAndShowMenu = () => { const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText(); let selectedText = getSelectedText();
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject) parentEpml.request('openCopyTextMenu', textMenuObject)
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
} }
isEmptyArray(arr) { isEmptyArray(arr) {
if (!arr) { return true } if (!arr) { return true }
return arr.length === 0 return arr.length === 0
} }
clearSelection() { clearSelection() {
window.getSelection().removeAllRanges() window.getSelection().removeAllRanges()
window.parent.getSelection().removeAllRanges() window.parent.getSelection().removeAllRanges()
} }
} }
window.customElements.define('puzzles-info', Puzzles) window.customElements.define('puzzles-info', Puzzles)

View File

@ -12,23 +12,23 @@ import '@polymer/paper-progress/paper-progress.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class WebBrowser extends LitElement { class WebBrowser extends LitElement {
static get properties() { static get properties() {
return { return {
url: { type: String }, url: { type: String },
name: { type: String }, name: { type: String },
service: { type: String }, service: { type: String },
identifier: { type: String }, identifier: { type: String },
followedNames: { type: Array }, followedNames: { type: Array },
blockedNames: { type: Array }, blockedNames: { type: Array }
} }
} }
static get observers() { static get observers() {
return ['_kmxKeyUp(amount)'] return ['_kmxKeyUp(amount)']
} }
static get styles() { static get styles() {
return css` return css`
* { * {
--mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary); --mdc-theme-secondary: var(--mdc-theme-primary);
@ -40,8 +40,6 @@ class WebBrowser extends LitElement {
} }
#websitesWrapper .buttons { #websitesWrapper .buttons {
/* --paper-button-ink-color: var(--paper-green-500);
color: var(--paper-green-500); */
width: auto !important; width: auto !important;
} }
@ -94,10 +92,10 @@ class WebBrowser extends LitElement {
} }
` `
} }
render() { render() {
return html` return html`
<div id="websitesWrapper" style="width:auto; padding:10px; background: #fff;"> <div id="websitesWrapper" style="width:auto; padding:10px; background: #fff;">
<div class="layout horizontal center"> <div class="layout horizontal center">
<div class="address-bar"> <div class="address-bar">
@ -118,9 +116,9 @@ class WebBrowser extends LitElement {
</div> </div>
</div> </div>
` `
} }
renderFollowUnfollowButton() { renderFollowUnfollowButton() {
// Only show the follow/unfollow button if we have permission to modify the list on this node // Only show the follow/unfollow button if we have permission to modify the list on this node
if (this.followedNames == null || !Array.isArray(this.followedNames)) { if (this.followedNames == null || !Array.isArray(this.followedNames)) {
return html`` return html``
@ -153,50 +151,50 @@ class WebBrowser extends LitElement {
} }
// Navigation // Navigation
goBack() { goBack() {
window.history.back(); window.history.back();
} }
goForward() { goForward() {
window.history.forward(); window.history.forward();
} }
refresh() { refresh() {
window.location.reload(); window.location.reload();
}
goBackToList() {
window.location="../index.html";
} }
follow() { goBackToList() {
this.followName(this.name); window.location = "../index.html";
} }
unfollow() { follow() {
this.unfollowName(this.name); this.followName(this.name);
} }
block() { unfollow() {
this.blockName(this.name); this.unfollowName(this.name);
} }
unblock() { block() {
this.unblockName(this.name); this.blockName(this.name);
} }
delete() { unblock() {
this.deleteCurrentResource(); this.unblockName(this.name);
}
delete() {
this.deleteCurrentResource();
} }
async followName(name) { async followName(name) {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
@ -225,7 +223,7 @@ class WebBrowser extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
@ -251,7 +249,7 @@ class WebBrowser extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
@ -280,7 +278,7 @@ class WebBrowser extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
@ -302,14 +300,14 @@ class WebBrowser extends LitElement {
return ret return ret
} }
async deleteCurrentResource() { async deleteCurrentResource() {
if (this.followedNames.indexOf(this.name) != -1) { if (this.followedNames.indexOf(this.name) != -1) {
// Following name - so deleting won't work // Following name - so deleting won't work
parentEpml.request('showSnackBar', "Can't delete data from followed names. Please unfollow first."); parentEpml.request('showSnackBar', "Can't delete data from followed names. Please unfollow first.");
return; return;
} }
let identifier = this.identifier == null ? "default" : resource.identifier; let identifier = this.identifier == null ? "default" : resource.identifier;
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/arbitrary/resource/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`, url: `/arbitrary/resource/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`,
@ -328,52 +326,51 @@ class WebBrowser extends LitElement {
// Helper Functions (Re-Used in Most part of the UI ) // Helper Functions (Re-Used in Most part of the UI )
textColor(color) { textColor(color) {
return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)'
} }
_textMenu(event) { _textMenu(event) {
const getSelectedText = () => { const getSelectedText = () => {
var text = '' var text = ''
if (typeof window.getSelection != 'undefined') { if (typeof window.getSelection != 'undefined') {
text = window.getSelection().toString() text = window.getSelection().toString()
} else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
text = this.shadowRoot.selection.createRange().text text = this.shadowRoot.selection.createRange().text
} }
return text return text
} }
const checkSelectedTextAndShowMenu = () => { const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText() let selectedText = getSelectedText()
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject) parentEpml.request('openCopyTextMenu', textMenuObject)
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
} }
constructor() { constructor() {
super() super()
this.url = 'about:blank' this.url = 'about:blank'
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
this.name = urlParams.get('name'); this.name = urlParams.get('name');
this.service = urlParams.get('service'); this.service = urlParams.get('service');
this.identifier = null; // FUTURE: add support for identifiers // FUTURE: add support for identifiers
this.identifier = null;
this.followedNames = [] this.followedNames = []
this.blockedNames = [] this.blockedNames = []
const getFollowedNames = async () => { const getFollowedNames = async () => {
// this.followedNames = []
let followedNames = await parentEpml.request('apiCall', { let followedNames = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}` url: `/lists/followedNames?apiKey=${this.getApiKey()}`
@ -384,7 +381,6 @@ class WebBrowser extends LitElement {
} }
const getBlockedNames = async () => { const getBlockedNames = async () => {
// this.blockedNames = []
let blockedNames = await parentEpml.request('apiCall', { let blockedNames = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}` url: `/lists/blockedNames?apiKey=${this.getApiKey()}`
@ -394,28 +390,28 @@ class WebBrowser extends LitElement {
setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval) setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval)
} }
const render = () => { const render = () => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
this.url = `${nodeUrl}/render/${this.service}/${this.name}`; this.url = `${nodeUrl}/render/${this.service}/${this.name}`;
} }
const authorizeAndRender = () => { const authorizeAndRender = () => {
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/render/authorize/${this.name}?apiKey=${this.getApiKey()}`, url: `/render/authorize/${this.name}?apiKey=${this.getApiKey()}`,
method: "POST" method: "POST"
}).then(res => { }).then(res => {
console.log(res) console.log(res)
if (res.error) { if (res.error) {
// Authorization problem - API key incorrect? // Authorization problem - API key incorrect?
} }
else { else {
render() render()
} }
}) })
} }
let configLoaded = false let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {} this.selectedAddress = {}
@ -424,10 +420,10 @@ class WebBrowser extends LitElement {
this.selectedAddress = selectedAddress this.selectedAddress = selectedAddress
}) })
parentEpml.subscribe('config', c => { parentEpml.subscribe('config', c => {
this.config = JSON.parse(c) this.config = JSON.parse(c)
if (!configLoaded) { if (!configLoaded) {
authorizeAndRender() authorizeAndRender()
setTimeout(getFollowedNames, 1) setTimeout(getFollowedNames, 1)
setTimeout(getBlockedNames, 1) setTimeout(getBlockedNames, 1)
configLoaded = true configLoaded = true
} }
@ -440,36 +436,36 @@ class WebBrowser extends LitElement {
} }
}) })
}) })
} }
firstUpdated() { firstUpdated() {
window.addEventListener('contextmenu', (event) => { window.addEventListener('contextmenu', (event) => {
event.preventDefault() event.preventDefault()
this._textMenu(event) this._textMenu(event)
}) })
window.addEventListener('click', () => { window.addEventListener('click', () => {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
}) })
window.onkeyup = (e) => { window.onkeyup = (e) => {
if (e.keyCode === 27) { if (e.keyCode === 27) {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
} }
} }
} }
getApiKey() { getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey;
return apiKey; return apiKey;
} }
clearSelection() { clearSelection() {
window.getSelection().removeAllRanges() window.getSelection().removeAllRanges()
window.parent.getSelection().removeAllRanges() window.parent.getSelection().removeAllRanges()
} }
} }
window.customElements.define('web-browser', WebBrowser) window.customElements.define('web-browser', WebBrowser)

View File

@ -32,6 +32,7 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background-color: #fff;
} }
</style> </style>
</head> </head>

View File

@ -4,9 +4,8 @@ import { Epml } from '../../../../epml'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/theme/material/all-imports.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -147,7 +146,7 @@ class DataManagement extends LitElement {
</div> </div>
<div class="divCard"> <div class="divCard">
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Data hosted by this node</h3> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Data hosted by this node</h3>
<vaadin-grid id="resourcesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.datres)}" page-size="20" height-by-rows> <vaadin-grid theme="compact" id="resourcesGrid" ?hidden="${this.isEmptyArray(this.datres)}" aria-label="Data Hosted" page-size="20" all-rows-visible>
<vaadin-grid-column header="Registered Name" path="name"></vaadin-grid-column> <vaadin-grid-column header="Registered Name" path="name"></vaadin-grid-column>
<vaadin-grid-column header="Service" path="service"></vaadin-grid-column> <vaadin-grid-column header="Service" path="service"></vaadin-grid-column>
<vaadin-grid-column header="Identifier" .renderer=${(root, column, data) => { <vaadin-grid-column header="Identifier" .renderer=${(root, column, data) => {

View File

@ -39,7 +39,6 @@
<body> <body>
<websites-list></websites-list> <websites-list></websites-list>
<script src="websites.js"></script> <script src="websites.js"></script>
</body> </body>

View File

@ -32,6 +32,7 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background-color: #fff;
} }
</style> </style>
</head> </head>

View File

@ -12,39 +12,37 @@ import '@polymer/paper-progress/paper-progress.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class PublishData extends LitElement { class PublishData extends LitElement {
static get properties() { static get properties() {
return { return {
name: { type: String }, name: { type: String },
service: { type: String }, service: { type: String },
identifier: { type: String }, identifier: { type: String },
category: { type: String }, category: { type: String },
uploadType: { type: String }, uploadType: { type: String },
showName: { type: Boolean }, showName: { type: Boolean },
showService: { type: Boolean }, showService: { type: Boolean },
showIdentifier: { type: Boolean }, showIdentifier: { type: Boolean },
serviceLowercase: { type: String }, serviceLowercase: { type: String },
names: { type: Array }, names: { type: Array },
registeredName: { type: String }, registeredName: { type: String },
selectedName: { type: String }, selectedName: { type: String },
path: { type: String }, path: { type: String },
portForwardingEnabled: { type: Boolean }, portForwardingEnabled: { type: Boolean },
//selectedAddress: { type: Object }, amount: { type: Number },
generalMessage: { type: String },
successMessage: { type: String },
errorMessage: { type: String },
loading: { type: Boolean },
btnDisable: { type: Boolean }
}
}
amount: { type: Number }, static get observers() {
generalMessage: { type: String }, return ['_kmxKeyUp(amount)']
successMessage: { type: String }, }
errorMessage: { type: String },
loading: { type: Boolean },
btnDisable: { type: Boolean },
}
}
static get observers() { static get styles() {
return ['_kmxKeyUp(amount)'] return css`
}
static get styles() {
return css`
* { * {
--mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary); --mdc-theme-secondary: var(--mdc-theme-primary);
@ -56,8 +54,6 @@ class PublishData extends LitElement {
} }
#publishWrapper .buttons { #publishWrapper .buttons {
/* --paper-button-ink-color: var(--paper-green-500);
color: var(--paper-green-500); */
width: auto !important; width: auto !important;
} }
@ -88,10 +84,10 @@ class PublishData extends LitElement {
width: 30px; width: 30px;
} }
` `
} }
render() { render() {
return html` return html`
<div id="publishWrapper" style="width:auto; padding:10px; background: #fff; height:100vh;"> <div id="publishWrapper" style="width:auto; padding:10px; background: #fff; height:100vh;">
<div class="layout horizontal center" style=" padding:12px 15px;"> <div class="layout horizontal center" style=" padding:12px 15px;">
<div class="address-bar"> <div class="address-bar">
@ -131,330 +127,330 @@ class PublishData extends LitElement {
</div> </div>
</div> </div>
` `
} }
// Navigation // Navigation
goBack() { goBack() {
window.history.back(); window.history.back();
} }
renderUploadField() { renderUploadField() {
if (this.uploadType === "file") { if (this.uploadType === "file") {
return html`<p> return html`<p>
<input style="width:100%;" id="file" type="file" /> <input style="width:100%;" id="file" type="file" />
</p>`; </p>`;
} }
else if (this.uploadType === "zip") { else if (this.uploadType === "zip") {
return html`<p> return html`<p>
<span class="upload-text">Select zip file containing static content:</span><br /> <span class="upload-text">Select zip file containing static content:</span><br />
<input style="width:100%;" id="file" type="file" accept=".zip" /> <input style="width:100%;" id="file" type="file" accept=".zip" />
</p>`; </p>`;
} }
else { else {
return html`<p> return html`<p>
<mwc-textfield style="width:100%;" label="Local path to static files" id="path" type="text" value="${this.path}"></mwc-textfield> <mwc-textfield style="width:100%;" label="Local path to static files" id="path" type="text" value="${this.path}"></mwc-textfield>
</p>`; </p>`;
} }
} }
doPublish(e) { doPublish(e) {
let registeredName = this.shadowRoot.getElementById('registeredName').value let registeredName = this.shadowRoot.getElementById('registeredName').value
let service = this.shadowRoot.getElementById('service').value let service = this.shadowRoot.getElementById('service').value
let identifier = this.shadowRoot.getElementById('identifier').value let identifier = this.shadowRoot.getElementById('identifier').value
// If name is hidden, use the value passed in via the name parameter // If name is hidden, use the value passed in via the name parameter
if (!this.showName) { if (!this.showName) {
registeredName = this.name registeredName = this.name
} }
let file; let file;
let path; let path;
if (this.uploadType === "file" || this.uploadType === "zip") { if (this.uploadType === "file" || this.uploadType === "zip") {
file = this.shadowRoot.getElementById('file').files[0] file = this.shadowRoot.getElementById('file').files[0]
} }
else if (this.uploadType === "path") { else if (this.uploadType === "path") {
path = this.shadowRoot.getElementById('path').value path = this.shadowRoot.getElementById('path').value
} }
this.generalMessage = '' this.generalMessage = ''
this.successMessage = '' this.successMessage = ''
this.errorMessage = '' this.errorMessage = ''
if (registeredName === '') { if (registeredName === '') {
this.showName = true this.showName = true
parentEpml.request('showSnackBar', 'Please select a registered name to publish data for') parentEpml.request('showSnackBar', 'Please select a registered name to publish data for')
} }
else if (this.uploadType === "file" && file == null) { else if (this.uploadType === "file" && file == null) {
parentEpml.request('showSnackBar', 'Please select a file to host') parentEpml.request('showSnackBar', 'Please select a file to host')
} }
else if (this.uploadType === "zip" && file == null) { else if (this.uploadType === "zip" && file == null) {
parentEpml.request('showSnackBar', 'Please select a zip file to host') parentEpml.request('showSnackBar', 'Please select a zip file to host')
} }
else if (this.uploadType === "path" && path === '') { else if (this.uploadType === "path" && path === '') {
parentEpml.request('showSnackBar', 'Please enter the directory path containing the static content') parentEpml.request('showSnackBar', 'Please enter the directory path containing the static content')
} }
else if (service === '') { else if (service === '') {
parentEpml.request('showSnackBar', 'Please enter a service name') parentEpml.request('showSnackBar', 'Please enter a service name')
} }
else { else {
this.publishData(registeredName, path, file, service, identifier) this.publishData(registeredName, path, file, service, identifier)
} }
} }
async publishData(registeredName, path, file, service, identifier) { async publishData(registeredName, path, file, service, identifier) {
this.loading = true this.loading = true
this.btnDisable = true this.btnDisable = true
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let nameRes = await parentEpml.request('apiCall', { let nameRes = await parentEpml.request('apiCall', {
type: 'api', type: 'api',
url: `/names/${receiverName}`, url: `/names/${receiverName}`,
}) })
return nameRes return nameRes
} }
const showError = async (errorMessage) => { const showError = async (errorMessage) => {
this.loading = false this.loading = false
this.btnDisable = false this.btnDisable = false
this.generalMessage = '' this.generalMessage = ''
this.successMessage = '' this.successMessage = ''
console.error(errorMessage) console.error(errorMessage)
} }
const validate = async () => { const validate = async () => {
let validNameRes = await validateName(registeredName) let validNameRes = await validateName(registeredName)
if (validNameRes.error) { if (validNameRes.error) {
this.errorMessage = "Error: " + validNameRes.message this.errorMessage = "Error: " + validNameRes.message
showError(this.errorMessage) showError(this.errorMessage)
throw new Error(this.errorMessage); throw new Error(this.errorMessage);
} }
this.generalMessage = "Processing data... this can take some time..."; this.generalMessage = "Processing data... this can take some time...";
let transactionBytes = await uploadData(registeredName, path, file) let transactionBytes = await uploadData(registeredName, path, file)
if (transactionBytes.error) { if (transactionBytes.error) {
this.errorMessage = "Error: " + transactionBytes.message this.errorMessage = "Error: " + transactionBytes.message
showError(this.errorMessage) showError(this.errorMessage)
throw new Error(this.errorMessage); throw new Error(this.errorMessage);
} }
else if (transactionBytes.includes("Error 500 Internal Server Error")) { else if (transactionBytes.includes("Error 500 Internal Server Error")) {
this.errorMessage = "Internal Server Error when publishing data" this.errorMessage = "Internal Server Error when publishing data"
showError(this.errorMessage) showError(this.errorMessage)
throw new Error(this.errorMessage); throw new Error(this.errorMessage);
} }
this.generalMessage = "Computing proof of work... this can take some time..."; this.generalMessage = "Computing proof of work... this can take some time...";
let signAndProcessRes = await signAndProcess(transactionBytes) let signAndProcessRes = await signAndProcess(transactionBytes)
if (signAndProcessRes.error) { if (signAndProcessRes.error) {
this.errorMessage = "Error: " + signAndProcessRes.message this.errorMessage = "Error: " + signAndProcessRes.message
showError(this.errorMessage) showError(this.errorMessage)
throw new Error(this.errorMessage); throw new Error(this.errorMessage);
} }
this.btnDisable = false this.btnDisable = false
this.loading = false this.loading = false
this.errorMessage = '' this.errorMessage = ''
this.generalMessage = '' this.generalMessage = ''
this.successMessage = 'Transaction successful!' this.successMessage = 'Transaction successful!'
} }
const uploadData = async (registeredName, path, file) => { const uploadData = async (registeredName, path, file) => {
let postBody = path let postBody = path
let urlSuffix = "" let urlSuffix = ""
if (file != null) { if (file != null) {
// If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API // If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API
if (this.uploadType === "zip") { if (this.uploadType === "zip") {
urlSuffix = "/zip" urlSuffix = "/zip"
} }
// If we're sending file data, use the /base64 version of the POST /arbitrary/* API // If we're sending file data, use the /base64 version of the POST /arbitrary/* API
else if (this.uploadType === "file") { else if (this.uploadType === "file") {
urlSuffix = "/base64" urlSuffix = "/base64"
} }
// Base64 encode the file to work around compatibility issues between javascript and java byte arrays // Base64 encode the file to work around compatibility issues between javascript and java byte arrays
let fileBuffer = new Uint8Array(await file.arrayBuffer()) let fileBuffer = new Uint8Array(await file.arrayBuffer())
postBody = Buffer.from(fileBuffer).toString('base64'); postBody = Buffer.from(fileBuffer).toString('base64');
} }
let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}` let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}`
if (identifier != null && identifier.trim().length > 0) { if (identifier != null && identifier.trim().length > 0) {
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}` uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}`
} }
let uploadDataRes = await parentEpml.request('apiCall', { let uploadDataRes = await parentEpml.request('apiCall', {
type: 'api', type: 'api',
method: 'POST', method: 'POST',
url: `${uploadDataUrl}?apiKey=${this.getApiKey()}`, url: `${uploadDataUrl}?apiKey=${this.getApiKey()}`,
body: `${postBody}`, body: `${postBody}`,
}) })
return uploadDataRes return uploadDataRes
} }
const convertBytesForSigning = async (transactionBytesBase58) => { const convertBytesForSigning = async (transactionBytesBase58) => {
let convertedBytes = await parentEpml.request('apiCall', { let convertedBytes = await parentEpml.request('apiCall', {
type: 'api', type: 'api',
method: 'POST', method: 'POST',
url: `/transactions/convert`, url: `/transactions/convert`,
body: `${transactionBytesBase58}`, body: `${transactionBytesBase58}`,
}) })
return convertedBytes return convertedBytes
} }
const signAndProcess = async (transactionBytesBase58) => { const signAndProcess = async (transactionBytesBase58) => {
let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58) let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58)
if (convertedBytesBase58.error) { if (convertedBytesBase58.error) {
this.errorMessage = "Error: " + convertedBytesBase58.message this.errorMessage = "Error: " + convertedBytesBase58.message
showError(this.errorMessage) showError(this.errorMessage)
throw new Error(this.errorMessage); throw new Error(this.errorMessage);
} }
const convertedBytes = window.parent.Base58.decode(convertedBytesBase58); const convertedBytes = window.parent.Base58.decode(convertedBytesBase58);
const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; }); const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; });
const convertedBytesArray = new Uint8Array(_convertedBytesArray) const convertedBytesArray = new Uint8Array(_convertedBytesArray)
const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result
const hashPtr = window.parent.sbrk(32, window.parent.heap); const hashPtr = window.parent.sbrk(32, window.parent.heap);
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32); const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
hashAry.set(convertedBytesHash); hashAry.set(convertedBytesHash);
const difficulty = 14; const difficulty = 14;
const workBufferLength = 8 * 1024 * 1024; const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap); const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
this.errorMessage = ''; this.errorMessage = '';
this.successMessage = ''; this.successMessage = '';
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty) let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
let response = await parentEpml.request('sign_arbitrary', { let response = await parentEpml.request('sign_arbitrary', {
nonce: this.selectedAddress.nonce, nonce: this.selectedAddress.nonce,
arbitraryBytesBase58: transactionBytesBase58, arbitraryBytesBase58: transactionBytesBase58,
arbitraryBytesForSigningBase58: convertedBytesBase58, arbitraryBytesForSigningBase58: convertedBytesBase58,
arbitraryNonce: nonce arbitraryNonce: nonce
}) })
let myResponse = { error: '' } let myResponse = { error: '' }
if (response === false) { if (response === false) {
myResponse.error = "Unable to sign and process transaction" myResponse.error = "Unable to sign and process transaction"
} }
else { else {
myResponse = response myResponse = response
} }
return myResponse return myResponse
} }
validate() validate()
} }
// Helper Functions (Re-Used in Most part of the UI ) // Helper Functions (Re-Used in Most part of the UI )
textColor(color) { textColor(color) {
return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)'
} }
_textMenu(event) { _textMenu(event) {
const getSelectedText = () => { const getSelectedText = () => {
var text = '' var text = ''
if (typeof window.getSelection != 'undefined') { if (typeof window.getSelection != 'undefined') {
text = window.getSelection().toString() text = window.getSelection().toString()
} else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
text = this.shadowRoot.selection.createRange().text text = this.shadowRoot.selection.createRange().text
} }
return text return text
} }
const checkSelectedTextAndShowMenu = () => { const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText() let selectedText = getSelectedText()
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject) parentEpml.request('openCopyTextMenu', textMenuObject)
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
} }
constructor() { constructor() {
super() super()
this.showName = false; this.showName = false;
this.showService = false this.showService = false
this.showIdentifier = false this.showIdentifier = false
const urlParams = new URLSearchParams(window.location.search) const urlParams = new URLSearchParams(window.location.search)
this.name = urlParams.get('name') this.name = urlParams.get('name')
this.service = urlParams.get('service') this.service = urlParams.get('service')
this.identifier = urlParams.get('identifier') this.identifier = urlParams.get('identifier')
this.category = urlParams.get('category') this.category = urlParams.get('category')
this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file" this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file"
if (urlParams.get('showName') === "true") { if (urlParams.get('showName') === "true") {
this.showName = true this.showName = true
} }
if (urlParams.get('showService') === "true") { if (urlParams.get('showService') === "true") {
this.showService = true this.showService = true
} }
if (urlParams.get('showIdentifier') === "true") { if (urlParams.get('showIdentifier') === "true") {
this.showIdentifier = true this.showIdentifier = true
} }
if (this.identifier != null) { if (this.identifier != null) {
if (this.identifier === "null" || this.identifier.trim().length == 0) { if (this.identifier === "null" || this.identifier.trim().length == 0) {
this.identifier = null this.identifier = null
} }
} }
this.portForwardingEnabled = true // Default to true so the message doesn't appear and disappear quickly // Default to true so the message doesn't appear and disappear quickly
this.names = [] this.portForwardingEnabled = true
this.registeredName = '' this.names = []
this.selectedName = 'invalid' this.registeredName = ''
this.path = '' this.selectedName = 'invalid'
//this.selectedAddress = {} this.path = ''
this.successMessage = '' this.successMessage = ''
this.generalMessage = '' this.generalMessage = ''
this.errorMessage = '' this.errorMessage = ''
this.loading = false this.loading = false
this.btnDisable = false this.btnDisable = false
const fetchNames = () => { const fetchNames = () => {
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/names/address/${this.selectedAddress.address}?limit=0&reverse=true` url: `/names/address/${this.selectedAddress.address}?limit=0&reverse=true`
}).then(res => { }).then(res => {
setTimeout(() => { setTimeout(() => {
this.names = res this.names = res
this.registeredName = res[0].name; this.registeredName = res[0].name;
}, 1) }, 1)
}) })
setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval) setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval)
} }
const fetchPeersSummary = () => { const fetchPeersSummary = () => {
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/peers/summary` url: `/peers/summary`
}).then(res => { }).then(res => {
setTimeout(() => { setTimeout(() => {
this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0); this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0);
}, 1) }, 1)
}) })
setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval) setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval)
} }
let configLoaded = false let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {} this.selectedAddress = {}
@ -465,7 +461,7 @@ class PublishData extends LitElement {
parentEpml.subscribe('config', c => { parentEpml.subscribe('config', c => {
if (!configLoaded) { if (!configLoaded) {
setTimeout(fetchNames, 1) setTimeout(fetchNames, 1)
setTimeout(fetchPeersSummary, 1) setTimeout(fetchPeersSummary, 1)
configLoaded = true configLoaded = true
} }
this.config = JSON.parse(c) this.config = JSON.parse(c)
@ -478,41 +474,41 @@ class PublishData extends LitElement {
} }
}) })
}) })
} }
firstUpdated() { firstUpdated() {
window.addEventListener('contextmenu', (event) => { window.addEventListener('contextmenu', (event) => {
event.preventDefault() event.preventDefault()
this._textMenu(event) this._textMenu(event)
}) })
window.addEventListener('click', () => { window.addEventListener('click', () => {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
}) })
window.onkeyup = (e) => { window.onkeyup = (e) => {
if (e.keyCode === 27) { if (e.keyCode === 27) {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
} }
} }
} }
selectName(e) { selectName(e) {
const name = this.shadowRoot.getElementById('registeredName').innerHTML const name = this.shadowRoot.getElementById('registeredName').innerHTML
this.selectedName = name this.selectedName = name
} }
getApiKey() { getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey;
return apiKey; return apiKey;
} }
clearSelection() { clearSelection() {
window.getSelection().removeAllRanges() window.getSelection().removeAllRanges()
window.parent.getSelection().removeAllRanges() window.parent.getSelection().removeAllRanges()
} }
} }
window.customElements.define('publish-data', PublishData) window.customElements.define('publish-data', PublishData)

View File

@ -5,9 +5,8 @@ import { Epml } from '../../../epml.js'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-textfield' import '@material/mwc-textfield'
import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/theme/material/all-imports.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -15,14 +14,14 @@ class Websites extends LitElement {
static get properties() { static get properties() {
return { return {
service: { type: String }, service: { type: String },
identifier: { type: String }, identifier: { type: String },
loading: { type: Boolean }, loading: { type: Boolean },
resources: { type: Array }, resources: { type: Array },
followedNames: { type: Array }, followedNames: { type: Array },
blockedNames: { type: Array }, blockedNames: { type: Array },
relayMode: { type: Boolean }, relayMode: { type: Boolean },
selectedAddress: { type: Object }, selectedAddress: { type: Object },
searchName: { type: String }, searchName: { type: String },
searchResources: { type: Array }, searchResources: { type: Array },
searchFollowedNames: { type: Array }, searchFollowedNames: { type: Array },
searchBlockedNames: { type: Array } searchBlockedNames: { type: Array }
@ -159,7 +158,7 @@ class Websites extends LitElement {
constructor() { constructor() {
super() super()
this.service = "WEBSITE" this.service = "WEBSITE"
this.identifier = null this.identifier = null
this.selectedAddress = {} this.selectedAddress = {}
this.resources = [] this.resources = []
this.followedNames = [] this.followedNames = []
@ -185,15 +184,15 @@ class Websites extends LitElement {
<mwc-textfield outlined label="Name To Search" id="searchName" type="text" value="${this.searchName}"></mwc-textfield>&nbsp;&nbsp;<br> <mwc-textfield outlined label="Name To Search" id="searchName" type="text" value="${this.searchName}"></mwc-textfield>&nbsp;&nbsp;<br>
<mwc-button raised icon="search" @click="${(e) => this.doSearch(e)}">Search</mwc-button> <mwc-button raised icon="search" @click="${(e) => this.doSearch(e)}">Search</mwc-button>
</div><br /> </div><br />
<vaadin-grid id="searchResourcesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.searchResources)}" .items="${this.searchResources}" height-by-rows> <vaadin-grid theme="compact" id="searchResourcesGrid" ?hidden="${this.isEmptyArray(this.searchResources)}" .items="${this.searchResources}" aria-label="Search Websites" all-rows-visible>
<vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => { <vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => {
render(html`${this.renderSearchAvatar(data.item)}`, root) render(html`${this.renderSearchAvatar(data.item)}`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
<vaadin-grid-column header="Name" .renderer=${(root, column, data) => { <vaadin-grid-column header="Name" .renderer=${(root, column, data) => {
render(html`${this.renderSearchName(data.item)}`, root) render(html`${this.renderSearchName(data.item)}`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
<vaadin-grid-column header="Status" .renderer=${(root, column, data) => { <vaadin-grid-column header="Status" .renderer=${(root, column, data) => {
render(html`${this.renderSearchStatus(data.item)}`, root) render(html`${this.renderSearchStatus(data.item)}`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
<vaadin-grid-column header="Size" .renderer=${(root, column, data) => { <vaadin-grid-column header="Size" .renderer=${(root, column, data) => {
render(html`${this.renderSearchSize(data.item)}`, root) render(html`${this.renderSearchSize(data.item)}`, root)
@ -205,10 +204,12 @@ class Websites extends LitElement {
render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root); render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root);
}}></vaadin-grid-column> }}></vaadin-grid-column>
</vaadin-grid><br /> </vaadin-grid><br />
</div>
<div class="divCard">
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Websites</h3> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Websites</h3>
<vaadin-grid id="resourcesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.resources)}" page-size="20" height-by-rows> <vaadin-grid theme="compact" id="resourcesGrid" ?hidden="${this.isEmptyArray(this.resources)}" aria-label="Websites" page-size="20" all-rows-visible>
<vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => { <vaadin-grid-column width="5rem" flex-grow="0" header="Avatar" .renderer=${(root, column, data) => {
render(html`${this.renderAvatar(data.item)}`, root) render(html`${this.renderAvatar(data.item)}`, root)
}}></vaadin-grid-column> }}></vaadin-grid-column>
<vaadin-grid-column header="Name" .renderer=${(root, column, data) => { <vaadin-grid-column header="Name" .renderer=${(root, column, data) => {
render(html`${this.renderName(data.item)}`, root) render(html`${this.renderName(data.item)}`, root)
@ -246,7 +247,7 @@ class Websites extends LitElement {
}) })
this.followedNames = followedNames this.followedNames = followedNames
setTimeout(getFollowedNames, this.config.user.nodeSettings.pingInterval) setTimeout(getFollowedNames, 60000)
} }
const getBlockedNames = async () => { const getBlockedNames = async () => {
@ -255,7 +256,7 @@ class Websites extends LitElement {
}) })
this.blockedNames = blockedNames this.blockedNames = blockedNames
setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval) setTimeout(getBlockedNames, 60000)
} }
const getSearchFollowedNames = async () => { const getSearchFollowedNames = async () => {
@ -264,7 +265,7 @@ class Websites extends LitElement {
}) })
this.searchFollowedNames = searchFollowedNames this.searchFollowedNames = searchFollowedNames
setTimeout(getSearchFollowedNames, this.config.user.nodeSettings.pingInterval) setTimeout(getSearchFollowedNames, 60000)
} }
const getSearchBlockedNames = async () => { const getSearchBlockedNames = async () => {
@ -273,7 +274,7 @@ class Websites extends LitElement {
}) })
this.searchBlockedNames = searchBlockedNames this.searchBlockedNames = searchBlockedNames
setTimeout(getSearchBlockedNames, this.config.user.nodeSettings.pingInterval) setTimeout(getSearchBlockedNames, 60000)
} }
const getRelayMode = async () => { const getRelayMode = async () => {
@ -282,7 +283,7 @@ class Websites extends LitElement {
}) })
this.relayMode = relayMode; this.relayMode = relayMode;
setTimeout(getRelayMode, this.config.user.nodeSettings.pingInterval) setTimeout(getRelayMode, 60000)
} }
@ -318,7 +319,7 @@ class Websites extends LitElement {
setTimeout(getSearchFollowedNames, 1) setTimeout(getSearchFollowedNames, 1)
setTimeout(getSearchBlockedNames, 1) setTimeout(getSearchBlockedNames, 1)
setTimeout(getRelayMode, 1) setTimeout(getRelayMode, 1)
setInterval(this.getArbitraryResources, 120 * 1000) setInterval(this.getArbitraryResources, 120000)
configLoaded = true configLoaded = true
} }
this.config = JSON.parse(c) this.config = JSON.parse(c)
@ -419,13 +420,13 @@ class Websites extends LitElement {
} }
doSearch(e) { doSearch(e) {
this.searchResult() this.searchResult()
} }
async searchResult() { async searchResult() {
let searchName = this.shadowRoot.getElementById('searchName').value let searchName = this.shadowRoot.getElementById('searchName').value
if (searchName.length === 0) { if (searchName.length === 0) {
parentEpml.request('showSnackBar', 'Name Can Not Be Empty!') parentEpml.request('showSnackBar', 'Name Can Not Be Empty!')
} else { } else {
let searchResources = await parentEpml.request('apiCall', { let searchResources = await parentEpml.request('apiCall', {
url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=5&reverse=false&includestatus=true` url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=5&reverse=false&includestatus=true`
@ -481,7 +482,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
method: 'POST', method: 'POST',
@ -505,7 +506,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
method: 'DELETE', method: 'DELETE',
@ -541,7 +542,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
method: 'POST', method: 'POST',
@ -565,7 +566,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
method: 'DELETE', method: 'DELETE',
@ -619,7 +620,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
@ -649,7 +650,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`, url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
@ -676,7 +677,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
@ -706,7 +707,7 @@ class Websites extends LitElement {
let items = [ let items = [
name name
] ]
let namesJsonString = JSON.stringify({"items": items}) let namesJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', { let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
@ -796,7 +797,7 @@ class Websites extends LitElement {
if (bytes == 0) return '0 bytes'; if (bytes == 0) return '0 bytes';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
} }
_textMenu(event) { _textMenu(event) {

View File

@ -32,14 +32,14 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background: #fff; background-color: #fff;
} }
</style> </style>
</head> </head>
<body> <body>
<reward-share></reward-share> <reward-share></reward-share>
<script type="module" src="reward-share.js"></script> <script src="reward-share.js"></script>
</body> </body>
</html> </html>

View File

@ -7,10 +7,9 @@ import '@material/mwc-button'
import '@material/mwc-textfield' import '@material/mwc-textfield'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@material/mwc-slider' import '@material/mwc-slider'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js' import '@vaadin/grid/theme/material/all-imports.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -43,6 +42,12 @@ class RewardShare extends LitElement {
padding: 12px 24px; padding: 12px 24px;
} }
.divCard {
border: 1px solid #eee;
padding: 1em;
box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20);
}
h2 { h2 {
margin:0; margin:0;
} }
@ -73,18 +78,21 @@ class RewardShare extends LitElement {
return html` return html`
<div id="reward-share-page"> <div id="reward-share-page">
<div style="min-height:48px; display: flex; padding-bottom: 6px;"> <div style="min-height:48px; display: flex; padding-bottom: 6px;">
<h3 style="margin: 0; flex: 1; padding-top: 8px; display: inline;">Rewardshares involving this account</h3> <h3 style="margin: 0; flex: 1; padding-top: 8px; display: inline;">Rewardshares</h3>
<mwc-button style="float:right;" @click=${() => this.shadowRoot.querySelector('#createRewardShareDialog').show()}><mwc-icon>add</mwc-icon>Create reward share</mwc-button> <mwc-button style="float:right;" @click=${() => this.shadowRoot.querySelector('#createRewardShareDialog').show()}><mwc-icon>add</mwc-icon>Create reward share</mwc-button>
</div> </div>
<vaadin-grid id="accountRewardSharesGrid" style="height:auto;" ?hidden="${this.isEmptyArray(this.rewardShares)}" .items="${this.rewardShares}" height-by-rows> <div class="divCard">
<vaadin-grid-column auto-width path="mintingAccount"></vaadin-grid-column> <h3 style="margin: 0; margin-bottom: 1em; text-align: center;">Rewardshares Involving In This Account</h3>
<vaadin-grid-column auto-width path="sharePercent"></vaadin-grid-column> <vaadin-grid theme="compact" id="accountRewardSharesGrid" ?hidden="${this.isEmptyArray(this.rewardShares)}" .items="${this.rewardShares}" all-rows-visible>
<vaadin-grid-column auto-width path="recipient"></vaadin-grid-column> <vaadin-grid-column auto-width path="mintingAccount"></vaadin-grid-column>
<vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => { <vaadin-grid-column auto-width path="sharePercent"></vaadin-grid-column>
render(html`${this.renderRemoveRewardShareButton(data.item)}`, root) <vaadin-grid-column auto-width path="recipient"></vaadin-grid-column>
}}></vaadin-grid-column> <vaadin-grid-column width="12em" header="Action" .renderer=${(root, column, data) => {
</vaadin-grid> render(html`${this.renderRemoveRewardShareButton(data.item)}`, root)
}}></vaadin-grid-column>
</vaadin-grid>
</div>
<mwc-dialog id="createRewardShareDialog" scrimClickAction="${this.createRewardShareLoading ? '' : 'close'}"> <mwc-dialog id="createRewardShareDialog" scrimClickAction="${this.createRewardShareLoading ? '' : 'close'}">
<div>Level 1 - 4 can create a Self Share and Level 5 or above can create a Reward Share!</div> <div>Level 1 - 4 can create a Self Share and Level 5 or above can create a Reward Share!</div>
@ -248,7 +256,7 @@ class RewardShare extends LitElement {
const recipientPublicKey = this.shadowRoot.getElementById("recipientPublicKey").value const recipientPublicKey = this.shadowRoot.getElementById("recipientPublicKey").value
const percentageShare = this.shadowRoot.getElementById("rewardSharePercentageSlider").value const percentageShare = this.shadowRoot.getElementById("rewardSharePercentageSlider").value
// Check for valid...^ // Check for valid...
this.createRewardShareLoading = true this.createRewardShareLoading = true
let recipientAddress = window.parent.base58PublicKeyToAddress(recipientPublicKey) let recipientAddress = window.parent.base58PublicKeyToAddress(recipientPublicKey)
@ -339,8 +347,8 @@ class RewardShare extends LitElement {
this.error = true this.error = true
this.message = `CANNOT CREATE SELF SHARE! at level ${accountDetails.level}` this.message = `CANNOT CREATE SELF SHARE! at level ${accountDetails.level}`
} }
} else { //Check for creating reward shares } else {
//Check for creating reward shares
if (accountDetails.level >= 5) { if (accountDetails.level >= 5) {
this.error = false this.error = false
@ -402,7 +410,7 @@ class RewardShare extends LitElement {
async removeRewardShare(rewardShareObject) { async removeRewardShare(rewardShareObject) {
const myPercentageShare = -1 const myPercentageShare = -1
// Check for valid...^ // Check for valid...
this.removeRewardShareLoading = true this.removeRewardShareLoading = true
// Get Last Ref // Get Last Ref

View File

@ -32,6 +32,7 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background-color: #fff;
} }
</style> </style>
</head> </head>

File diff suppressed because it is too large Load Diff

View File

@ -15,20 +15,20 @@ blockTests.push((block, addr) => {
}) })
export class AddressWatcher { export class AddressWatcher {
constructor (addresses) { constructor(addresses) {
addresses = addresses || [] addresses = addresses || []
this.reset() this.reset()
addresses.forEach(addr => this.addAddress(addr)) addresses.forEach(addr => this.addAddress(addr))
} }
reset () { reset() {
this._addresses = {} this._addresses = {}
this._addressStreams = {} this._addressStreams = {}
} }
// Adds an address to watch // Adds an address to watch
addAddress (address) { addAddress(address) {
const addr = address.address const addr = address.address
this._addresses[addr] = address this._addresses[addr] = address
@ -37,7 +37,7 @@ export class AddressWatcher {
this.updateAddress(addr) this.updateAddress(addr)
} }
async testBlock (block) { async testBlock(block) {
const pendingUpdateAddresses = [] const pendingUpdateAddresses = []
const transactions = await parentEpml.request('apiCall', { url: `/transactions/block/${block.signature}` }) const transactions = await parentEpml.request('apiCall', { url: `/transactions/block/${block.signature}` })
transactions.forEach(transaction => { transactions.forEach(transaction => {
@ -57,7 +57,7 @@ export class AddressWatcher {
pendingUpdateAddresses.forEach(addr => this.updateAddress(addr)) pendingUpdateAddresses.forEach(addr => this.updateAddress(addr))
} }
async updateAddress (addr) { async updateAddress(addr) {
let addressRequest = await parentEpml.request('apiCall', { let addressRequest = await parentEpml.request('apiCall', {
type: 'explorer', type: 'explorer',
data: { data: {

View File

@ -1,7 +1,7 @@
import { parentEpml } from '../connect.js' import { parentEpml } from '../connect.js'
export class UnconfirmedTransactionWatcher { export class UnconfirmedTransactionWatcher {
constructor () { constructor() {
this._unconfirmedTransactionStreams = {} this._unconfirmedTransactionStreams = {}
this.reset() // Sets defaults this.reset() // Sets defaults
@ -10,13 +10,13 @@ export class UnconfirmedTransactionWatcher {
}, 10 * 1000) }, 10 * 1000)
} }
reset () { reset() {
this._addresses = {} this._addresses = {}
this._addressesUnconfirmedTransactions = {} this._addressesUnconfirmedTransactions = {}
} }
// Adds an address to watch // Adds an address to watch
addAddress (address) { addAddress(address) {
const addr = address.address const addr = address.address
this._addresses[addr] = address this._addresses[addr] = address
this._addressesUnconfirmedTransactions[addr] = [] this._addressesUnconfirmedTransactions[addr] = []
@ -24,13 +24,13 @@ export class UnconfirmedTransactionWatcher {
this._unconfirmedTransactionStreams[addr] = new EpmlStream(`unconfirmedOfAddress/${addr}`, () => this._addressesUnconfirmedTransactions[addr]) this._unconfirmedTransactionStreams[addr] = new EpmlStream(`unconfirmedOfAddress/${addr}`, () => this._addressesUnconfirmedTransactions[addr])
} }
check () { check() {
const c = this._addressTransactionCheck() const c = this._addressTransactionCheck()
.then(() => setTimeout(() => this.check(), 5000)) .then(() => setTimeout(() => this.check(), 5000))
.catch(() => setTimeout(() => this.check(), 5000)) .catch(() => setTimeout(() => this.check(), 5000))
} }
async _addressTransactionCheck () { async _addressTransactionCheck() {
return Promise.all(Object.keys(this._addresses).map(addr => { return Promise.all(Object.keys(this._addresses).map(addr => {
return parentEpml.request('apiCall', { return parentEpml.request('apiCall', {
type: 'api', type: 'api',

View File

@ -3,7 +3,6 @@
<head> <head>
<link rel="stylesheet" href="/font/material-icons.css"> <link rel="stylesheet" href="/font/material-icons.css">
<meta charset="UTF-8">
<style> <style>
html { html {
--scrollbarBG: #a1a1a1; --scrollbarBG: #a1a1a1;
@ -33,14 +32,14 @@
body { body {
margin: 0; margin: 0;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
background: #fff; background-color: #fff;
} }
</style> </style>
</head> </head>
<body> <body>
<trade-portal></trade-portal> <trade-portal></trade-portal>
<script type="module" src="trade-portal.js"></script> <script src="trade-portal.js"></script>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,45 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<link rel="stylesheet" href="/font/material-icons.css" />
<style>
html {
--scrollbarBG: #a1a1a1;
--thumbBG: #6a6c75;
}
*::-webkit-scrollbar { <head>
width: 11px; <link rel="stylesheet" href="/font/material-icons.css">
} <style>
html {
--scrollbarBG: #a1a1a1;
--thumbBG: #6a6c75;
}
* { *::-webkit-scrollbar {
scrollbar-width: thin; width: 11px;
scrollbar-color: var(--thumbBG) var(--scrollbarBG); }
}
*::-webkit-scrollbar-track { * {
background: var(--scrollbarBG); scrollbar-width: thin;
} scrollbar-color: var(--thumbBG) var(--scrollbarBG);
}
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-track {
background-color: var(--thumbBG); background: var(--scrollbarBG);
border-radius: 6px; }
border: 3px solid var(--scrollbarBG);
}
html, *::-webkit-scrollbar-thumb {
body { background-color: var(--thumbBG);
margin: 0; border-radius: 6px;
background: white; border: 3px solid var(--scrollbarBG);
font-family: 'Roboto', sans-serif; }
}
</style> html,
</head> body {
margin: 0;
font-family: "Roboto", sans-serif;
background-color: #fff;
}
</style>
</head>
<body>
<multi-wallet></multi-wallet>
<script src="wallet-app.js"></script>
</body>
<body>
<multi-wallet></multi-wallet>
<script src="wallet-app.js"></script>
</body>
</html> </html>

View File

@ -3,37 +3,35 @@ import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import '../components/ButtonIconCopy' import '../components/ButtonIconCopy'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/vaadin-grid/vaadin-grid.js' import '@vaadin/grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/theme/material/all-imports.js' import '@vaadin/grid/theme/material/all-imports.js'
import '@github/time-elements' import '@github/time-elements'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const coinsNames=['qort','btc','ltc','doge']
const coinsNames = ['qort', 'btc', 'ltc', 'doge']
class MultiWallet extends LitElement { class MultiWallet extends LitElement {
static get properties() { static get properties() {
return { return {
loading: { type: Boolean }, loading: { type: Boolean },
transactions: { type: Object }, transactions: { type: Object },
lastBlock: { type: Object }, lastBlock: { type: Object },
selectedTransaction: { type: Object }, selectedTransaction: { type: Object },
isTextMenuOpen: { type: Boolean }, isTextMenuOpen: { type: Boolean },
wallets:{type : Map}, wallets: { type: Map },
_selectedWallet:'qort', _selectedWallet: 'qort',
balanceString:'Fetching balance ...' balanceString: 'Fetching balance ...'
} }
} }
static get styles() { static get styles() {
return [ return [
css` css`
#pages { #pages {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -114,7 +112,6 @@ class MultiWallet extends LitElement {
table td, table td,
th { th {
white-space: nowrap; white-space: nowrap;
/* padding:10px; */
text-align: left; text-align: left;
font-size: 14px; font-size: 14px;
padding: 0 12px; padding: 0 12px;
@ -151,8 +148,6 @@ class MultiWallet extends LitElement {
padding: 0; padding: 0;
} }
#transactionList > * { #transactionList > * {
/* padding-left:24px;
padding-right:24px; */
} }
.color-in { .color-in {
color: #02977e; color: #02977e;
@ -254,7 +249,6 @@ class MultiWallet extends LitElement {
border-top: 1px solid #e5e5e5; border-top: 1px solid #e5e5e5;
padding-top: 0px; padding-top: 0px;
height: 100%; height: 100%;
/* overflow: auto; */
} }
.show { .show {
@ -339,7 +333,7 @@ class MultiWallet extends LitElement {
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
border-radius: 3px; border-radius: 3px;
filter: grayscale(100%); filter: grayscale(100%);
} }
.currency-box.active .currency-image, .currency-box.active .currency-image,
.currency-box:hover .currency-image { .currency-box:hover .currency-image {
@ -473,65 +467,64 @@ class MultiWallet extends LitElement {
} }
} }
`, `,
] ]
} }
constructor() { constructor() {
super() super()
this.lastBlock = { this.lastBlock = {
height: 0, height: 0,
} }
this.selectedTransaction = {} this.selectedTransaction = {}
this.isTextMenuOpen = false this.isTextMenuOpen = false
this.loading = true this.loading = true
this.selectWallet = this.selectWallet.bind(this) this.selectWallet = this.selectWallet.bind(this)
this.wallets=new Map() this.wallets = new Map()
let coinProp={ let coinProp = {
balance:0, balance: 0,
wallet:null, wallet: null,
transactions:[], transactions: [],
fetchingWalletBalance:false, fetchingWalletBalance: false,
fetchingWalletTransactions:false fetchingWalletTransactions: false
} }
coinsNames.forEach((c,i)=>{//reset fetching status, c:coin, i:index coinsNames.forEach((c, i) => {
this.wallets.set(c,{...coinProp}) this.wallets.set(c, { ...coinProp })
},this)//thisArg=this }, this)
this.wallets.get('qort').wallet = window.parent.reduxStore.getState().app.selectedAddress this.wallets.get('qort').wallet = window.parent.reduxStore.getState().app.selectedAddress
this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet
this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet
this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet
this._selectedWallet='qort' this._selectedWallet = 'qort'
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async (selectedAddress) => { parentEpml.subscribe('selected_address', async (selectedAddress) => {
selectedAddress = JSON.parse(selectedAddress) selectedAddress = JSON.parse(selectedAddress)
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
this.wallets.get('qort').wallet = selectedAddress this.wallets.get('qort').wallet = selectedAddress
this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet
this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet
this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet
// this.updateAccountTransactions(); })
})
parentEpml.subscribe('copy_menu_switch', async (value) => { parentEpml.subscribe('copy_menu_switch', async (value) => {
if (value === 'false' && this.isTextMenuOpen === true) { if (value === 'false' && this.isTextMenuOpen === true) {
this.clearSelection() this.clearSelection()
this.isTextMenuOpen = false this.isTextMenuOpen = false
} }
}) })
}) })
} }
render() { render() {
return html` return html`
<div class="wrapper"> <div class="wrapper">
<div class="wallet"> <div class="wallet">
<div style="font-size: 20px; color: #777; padding: 16px; border-bottom: 1px solid #eee;">Wallets</div> <div style="font-size: 20px; color: #777; padding: 16px; border-bottom: 1px solid #eee;">Wallets</div>
@ -599,13 +592,11 @@ class MultiWallet extends LitElement {
<span class="title">Receiver</span> <span class="title">Receiver</span>
<br /> <br />
<div><span class="">${this.selectedTransaction.recipient}</span></div> <div><span class="">${this.selectedTransaction.recipient}</span></div>
${!this.selectedTransaction.amount ${!this.selectedTransaction.amount ? '' : html`
? '' <span class="title">Amount</span>
: html` <br />
<span class="title">Amount</span> <div><span class="">${this.selectedTransaction.amount} QORT</span></div>
<br /> `}
<div><span class="">${this.selectedTransaction.amount} QORT</span></div>
`}
<span class="title"> Transaction Fee </span> <span class="title"> Transaction Fee </span>
<br /> <br />
<div><span class="">${this.selectedTransaction.fee}</span></div> <div><span class="">${this.selectedTransaction.fee}</span></div>
@ -626,52 +617,52 @@ class MultiWallet extends LitElement {
</div> </div>
</div> </div>
` `
} }
getSelectedWalletAddress() { getSelectedWalletAddress() {
return this._selectedWallet === 'qort' return this._selectedWallet === 'qort'
? this.wallets.get(this._selectedWallet).wallet.address ? this.wallets.get(this._selectedWallet).wallet.address
: this.wallets.get(this._selectedWallet).wallet.address : this.wallets.get(this._selectedWallet).wallet.address
} }
async getTransactionGrid(coin) { async getTransactionGrid(coin) {
this.transactionsGrid = this.shadowRoot.querySelector(`#${coin}TransactionsGrid`) this.transactionsGrid = this.shadowRoot.querySelector(`#${coin}TransactionsGrid`)
if (coin === 'qort') { if (coin === 'qort') {
this.transactionsGrid.addEventListener( this.transactionsGrid.addEventListener(
'click', 'click',
(e) => { (e) => {
let myItem = this.transactionsGrid.getEventContext(e).item let myItem = this.transactionsGrid.getEventContext(e).item
this.showTransactionDetails(myItem, this.wallets.get(this._selectedWallet).transactions) this.showTransactionDetails(myItem, this.wallets.get(this._selectedWallet).transactions)
}, },
{ passive: true } { passive: true }
) )
} }
this.pagesControl = this.shadowRoot.querySelector('#pages') this.pagesControl = this.shadowRoot.querySelector('#pages')
this.pages = undefined this.pages = undefined
} }
async renderTransactions() { async renderTransactions() {
if (this._selectedWallet === 'qort') { if (this._selectedWallet === 'qort') {
render(this.renderQortTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) render(this.renderQortTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
} else { } else {
render(this.renderBTCLikeTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) render(this.renderBTCLikeTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
} }
} }
renderQortTransactions(transactions, coin) { renderQortTransactions(transactions, coin) {
const requiredConfirmations = 3 // arbitrary value const requiredConfirmations = 3 // arbitrary value
// initially `currentBlockHeight` might not be set in the store // initially `currentBlockHeight` might not be set in the store
const currentBlockHeight = window.parent.reduxStore.getState().app.blockInfo.height const currentBlockHeight = window.parent.reduxStore.getState().app.blockInfo.height
if (Array.isArray(transactions)) { if (Array.isArray(transactions)) {
transactions = transactions.map(tx => { transactions = transactions.map(tx => {
tx.confirmations = (currentBlockHeight - (tx.blockHeight - 1)) || '' tx.confirmations = (currentBlockHeight - (tx.blockHeight - 1)) || ''
return tx return tx
}) })
} }
return html` return html`
<dom-module id="vaadin-grid-qort-theme" theme-for="vaadin-grid"> <dom-module id="vaadin-grid-qort-theme" theme-for="vaadin-grid">
<template> <template>
<style> <style>
@ -685,20 +676,20 @@ class MultiWallet extends LitElement {
</template> </template>
</dom-module> </dom-module>
<div style="padding-left:12px;" ?hidden="${!this.isEmptyArray(transactions)}">Address has no transactions yet.</div> <div style="padding-left:12px;" ?hidden="${!this.isEmptyArray(transactions)}">Address has no transactions yet.</div>
<vaadin-grid theme="${coin}" id="${coin}TransactionsGrid" ?hidden="${this.isEmptyArray(this.wallets.get(this._selectedWallet).transactions)}" page-size="20" height-by-rows> <vaadin-grid theme="${coin}" id="${coin}TransactionsGrid" ?hidden="${this.isEmptyArray(this.wallets.get(this._selectedWallet).transactions)}" page-size="20" all-rows-visible>
<vaadin-grid-column <vaadin-grid-column
auto-width auto-width
.renderer=${(root, column, data) => { .renderer=${(root, column, data) => {
if (!currentBlockHeight) { if (!currentBlockHeight) {
return render(html``, root) return render(html``, root)
} }
const confirmed = data.item.confirmations >= requiredConfirmations const confirmed = data.item.confirmations >= requiredConfirmations
if (confirmed) { if (confirmed) {
render(html`<mwc-icon title="${ data.item.confirmations } Confirmations" style="color: #00C851">check</mwc-icon>`, root) render(html`<mwc-icon title="${data.item.confirmations} Confirmations" style="color: #00C851">check</mwc-icon>`, root)
} else { } else {
render(html`<mwc-icon title="${ data.item.confirmations || 0 }/${ requiredConfirmations } Confirmations" style="color: #777">schedule</mwc-icon>`, root) render(html`<mwc-icon title="${data.item.confirmations || 0}/${requiredConfirmations} Confirmations" style="color: #777">schedule</mwc-icon>`, root)
} }
}} }}
> >
</vaadin-grid-column> </vaadin-grid-column>
<vaadin-grid-column <vaadin-grid-column
@ -706,8 +697,8 @@ class MultiWallet extends LitElement {
resizable resizable
header="Type" header="Type"
.renderer=${(root, column, data) => { .renderer=${(root, column, data) => {
render(html` ${data.item.type} ${data.item.creatorAddress === this.wallets.get('qort').wallet.address ? html`<span class="color-out">OUT</span>` : html`<span class="color-in">IN</span>`} `, root) render(html` ${data.item.type} ${data.item.creatorAddress === this.wallets.get('qort').wallet.address ? html`<span class="color-out">OUT</span>` : html`<span class="color-in">IN</span>`} `, root)
}} }}
> >
</vaadin-grid-column> </vaadin-grid-column>
<vaadin-grid-column auto-width resizable header="Sender" path="creatorAddress"></vaadin-grid-column> <vaadin-grid-column auto-width resizable header="Sender" path="creatorAddress"></vaadin-grid-column>
@ -719,29 +710,29 @@ class MultiWallet extends LitElement {
resizable resizable
header="Time" header="Time"
.renderer=${(root, column, data) => { .renderer=${(root, column, data) => {
const time = new Date(data.item.timestamp) const time = new Date(data.item.timestamp)
render(html` <time-ago datetime=${time.toISOString()}> </time-ago> `, root) render(html` <time-ago datetime=${time.toISOString()}> </time-ago> `, root)
}} }}
> >
</vaadin-grid-column> </vaadin-grid-column>
</vaadin-grid> </vaadin-grid>
<div id="pages"></div> <div id="pages"></div>
` `
} }
renderBTCLikeTransactions(transactions, coin) { renderBTCLikeTransactions(transactions, coin) {
return html` return html`
<div style="padding-left:12px;" ?hidden="${!this.isEmptyArray(transactions)}">Address has no transactions yet.</div> <div style="padding-left:12px;" ?hidden="${!this.isEmptyArray(transactions)}">Address has no transactions yet.</div>
<vaadin-grid id="${coin}TransactionsGrid" ?hidden="${this.isEmptyArray(this.wallets.get(this._selectedWallet).transactions)}" page-size="20" height-by-rows> <vaadin-grid id="${coin}TransactionsGrid" ?hidden="${this.isEmptyArray(this.wallets.get(this._selectedWallet).transactions)}" page-size="20" all-rows-visible>
<vaadin-grid-column auto-width resizable header="Transaction Hash" path="txHash"></vaadin-grid-column> <vaadin-grid-column auto-width resizable header="Transaction Hash" path="txHash"></vaadin-grid-column>
<vaadin-grid-column <vaadin-grid-column
auto-width auto-width
resizable resizable
header="Total Amount" header="Total Amount"
.renderer=${(root, column, data) => { .renderer=${(root, column, data) => {
const amount = (Number(data.item.totalAmount) / 1e8).toFixed(8) const amount = (Number(data.item.totalAmount) / 1e8).toFixed(8)
render(html`${amount}`, root) render(html`${amount}`, root)
}} }}
> >
</vaadin-grid-column> </vaadin-grid-column>
<vaadin-grid-column <vaadin-grid-column
@ -749,122 +740,122 @@ class MultiWallet extends LitElement {
resizable resizable
header="Time" header="Time"
.renderer=${(root, column, data) => { .renderer=${(root, column, data) => {
const time = new Date(data.item.timestamp * 1000) const time = new Date(data.item.timestamp * 1000)
render(html` <time-ago datetime=${time.toISOString()}> </time-ago> `, root) render(html` <time-ago datetime=${time.toISOString()}> </time-ago> `, root)
}} }}
> >
</vaadin-grid-column> </vaadin-grid-column>
</vaadin-grid> </vaadin-grid>
<div id="pages"></div> <div id="pages"></div>
` `
} }
async updateItemsFromPage(page, changeWallet = false) { async updateItemsFromPage(page, changeWallet = false) {
if (page === undefined) { if (page === undefined) {
return return
} }
changeWallet === true ? (this.pagesControl.innerHTML = '') : null changeWallet === true ? (this.pagesControl.innerHTML = '') : null
if (!this.pages) { if (!this.pages) {
this.pages = Array.apply(null, { length: Math.ceil(this.wallets.get(this._selectedWallet).transactions.length / this.transactionsGrid.pageSize) }).map((item, index) => { this.pages = Array.apply(null, { length: Math.ceil(this.wallets.get(this._selectedWallet).transactions.length / this.transactionsGrid.pageSize) }).map((item, index) => {
return index + 1 return index + 1
}) })
const prevBtn = document.createElement('button') const prevBtn = document.createElement('button')
prevBtn.textContent = '<' prevBtn.textContent = '<'
prevBtn.addEventListener('click', () => { prevBtn.addEventListener('click', () => {
const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent) const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent)
this.updateItemsFromPage(selectedPage - 1) this.updateItemsFromPage(selectedPage - 1)
}) })
this.pagesControl.appendChild(prevBtn) this.pagesControl.appendChild(prevBtn)
this.pages.forEach((pageNumber) => { this.pages.forEach((pageNumber) => {
const pageBtn = document.createElement('button') const pageBtn = document.createElement('button')
pageBtn.textContent = pageNumber pageBtn.textContent = pageNumber
pageBtn.addEventListener('click', (e) => { pageBtn.addEventListener('click', (e) => {
this.updateItemsFromPage(parseInt(e.target.textContent)) this.updateItemsFromPage(parseInt(e.target.textContent))
}) })
if (pageNumber === page) { if (pageNumber === page) {
pageBtn.setAttribute('selected', true) pageBtn.setAttribute('selected', true)
} }
this.pagesControl.appendChild(pageBtn) this.pagesControl.appendChild(pageBtn)
}) })
const nextBtn = window.document.createElement('button') const nextBtn = window.document.createElement('button')
nextBtn.textContent = '>' nextBtn.textContent = '>'
nextBtn.addEventListener('click', () => { nextBtn.addEventListener('click', () => {
const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent) const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent)
this.updateItemsFromPage(selectedPage + 1) this.updateItemsFromPage(selectedPage + 1)
}) })
this.pagesControl.appendChild(nextBtn) this.pagesControl.appendChild(nextBtn)
} }
const buttons = Array.from(this.pagesControl.children) const buttons = Array.from(this.pagesControl.children)
buttons.forEach((btn, index) => { buttons.forEach((btn, index) => {
if (parseInt(btn.textContent) === page) { if (parseInt(btn.textContent) === page) {
btn.setAttribute('selected', true) btn.setAttribute('selected', true)
} else { } else {
btn.removeAttribute('selected') btn.removeAttribute('selected')
} }
if (index === 0) { if (index === 0) {
if (page === 1) { if (page === 1) {
btn.setAttribute('disabled', '') btn.setAttribute('disabled', '')
} else { } else {
btn.removeAttribute('disabled') btn.removeAttribute('disabled')
} }
} }
if (index === buttons.length - 1) { if (index === buttons.length - 1) {
if (page === this.pages.length) { if (page === this.pages.length) {
btn.setAttribute('disabled', '') btn.setAttribute('disabled', '')
} else { } else {
btn.removeAttribute('disabled') btn.removeAttribute('disabled')
} }
} }
}) })
let start = (page - 1) * this.transactionsGrid.pageSize let start = (page - 1) * this.transactionsGrid.pageSize
let end = page * this.transactionsGrid.pageSize let end = page * this.transactionsGrid.pageSize
this.transactionsGrid.items = this.wallets.get(this._selectedWallet).transactions.slice(start, end) this.transactionsGrid.items = this.wallets.get(this._selectedWallet).transactions.slice(start, end)
} }
_textMenu(event) { _textMenu(event) {
const getSelectedText = () => { const getSelectedText = () => {
var text = '' var text = ''
if (typeof window.getSelection != 'undefined') { if (typeof window.getSelection != 'undefined') {
text = window.getSelection().toString() text = window.getSelection().toString()
} else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
text = this.shadowRoot.selection.createRange().text text = this.shadowRoot.selection.createRange().text
} }
return text return text
} }
const checkSelectedTextAndShowMenu = () => { const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText() let selectedText = getSelectedText()
if (selectedText && typeof selectedText === 'string') { if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject) parentEpml.request('openCopyTextMenu', textMenuObject)
} }
} }
checkSelectedTextAndShowMenu() checkSelectedTextAndShowMenu()
} }
getApiKey() { getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey;
return apiKey; return apiKey;
} }
clearSelection() { clearSelection() {
window.getSelection().removeAllRanges() window.getSelection().removeAllRanges()
window.parent.getSelection().removeAllRanges() window.parent.getSelection().removeAllRanges()
} }
transactionItem(transactionObject) { transactionItem(transactionObject) {
return ` return `
<div class='transaction-item ${transactionObject.type}'> <div class='transaction-item ${transactionObject.type}'>
<div class='transaction-item_details'> <div class='transaction-item_details'>
<h3>${transactionObject.name}</h3> <h3>${transactionObject.name}</h3>
@ -875,193 +866,197 @@ class MultiWallet extends LitElement {
</div> </div>
</div> </div>
` `
} }
firstUpdated() { firstUpdated() {
// DOM refs // DOM refs
this.currencyBoxes = this.shadowRoot.querySelectorAll('.currency-box') this.currencyBoxes = this.shadowRoot.querySelectorAll('.currency-box')
this.transactionsDOM = this.shadowRoot.getElementById('transactionsDOM') this.transactionsDOM = this.shadowRoot.getElementById('transactionsDOM')
// Attach eventlisteners to the cuurency boxes // Attach eventlisteners to the cuurency boxes
this.currencyBoxes.forEach((currencyBox) => { this.currencyBoxes.forEach((currencyBox) => {
currencyBox.addEventListener('click', this.selectWallet) currencyBox.addEventListener('click', this.selectWallet)
}) })
this.showWallet() this.showWallet()
window.addEventListener('contextmenu', (event) => { window.addEventListener('contextmenu', (event) => {
event.preventDefault() event.preventDefault()
this.isTextMenuOpen = true this.isTextMenuOpen = true
this._textMenu(event) this._textMenu(event)
}) })
window.addEventListener('click', () => { window.addEventListener('click', () => {
if (this.isTextMenuOpen) { if (this.isTextMenuOpen) {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
} }
}) })
window.onkeyup = (e) => { window.onkeyup = (e) => {
if (e.keyCode === 27) { if (e.keyCode === 27) {
parentEpml.request('closeCopyTextMenu', null) parentEpml.request('closeCopyTextMenu', null)
} }
} }
} }
selectWallet(event) { selectWallet(event) {
event.preventDefault() event.preventDefault()
const target = event.currentTarget const target = event.currentTarget
// if (target.classList.contains('active')) return // if (target.classList.contains('active')) return
// removed to allow one click wallet refresh // removed to allow one click wallet refresh
this.currencyBoxes.forEach((currencyBox) => { this.currencyBoxes.forEach((currencyBox) => {
if (currencyBox.classList.contains('active')) { if (currencyBox.classList.contains('active')) {
currencyBox.classList.remove('active') currencyBox.classList.remove('active')
} }
}) })
target.classList.add('active') target.classList.add('active')
this._selectedWallet=target.attributes.coin.value this._selectedWallet = target.attributes.coin.value
this.showWallet() this.showWallet()
} }
async showWallet(){ async showWallet() {
this.transactionsDOM.hidden = true this.transactionsDOM.hidden = true
this.loading = true this.loading = true
if (this._selectedWallet=='qort') { if (this._selectedWallet == 'qort') {
if (!window.parent.reduxStore.getState().app.blockInfo.height) { if (!window.parent.reduxStore.getState().app.blockInfo.height) {
// we make sure that `blockHeight` is set before rendering QORT transactions // we make sure that `blockHeight` is set before rendering QORT transactions
await parentEpml.request('apiCall', { url: `/blocks/height`, type: 'api' }) await parentEpml.request('apiCall', { url: `/blocks/height`, type: 'api' })
.then(height => parentEpml.request('updateBlockInfo', { height })) .then(height => parentEpml.request('updateBlockInfo', { height }))
} }
} }
const coin=this._selectedWallet const coin = this._selectedWallet
await this.fetchWalletDetails(this._selectedWallet) await this.fetchWalletDetails(this._selectedWallet)
if(this._selectedWallet == coin){//if the wallet didn't switch if (this._selectedWallet == coin) {
await this.renderTransactions() //if the wallet didn't switch
await this.getTransactionGrid(this._selectedWallet) await this.renderTransactions()
await this.updateItemsFromPage(1, true) await this.getTransactionGrid(this._selectedWallet)
this.loading = false await this.updateItemsFromPage(1, true)
this.transactionsDOM.hidden = false this.loading = false
} this.transactionsDOM.hidden = false
} }
async fetchWalletDetails(coin){//this function will fetch the balance and transactions of the given wallet }
this.balanceString="Fetching balance ..." async fetchWalletDetails(coin) {
switch (coin) { //this function will fetch the balance and transactions of the given wallet
case 'qort': this.balanceString = "Fetching balance ..."
//fetching the qort balance switch (coin) {
parentEpml case 'qort':
.request('apiCall', { //fetching the qort balance
url: `/addresses/balance/${this.wallets.get('qort').wallet.address}?apiKey=${this.getApiKey()}`, parentEpml
}) .request('apiCall', {
.then((res) => { url: `/addresses/balance/${this.wallets.get('qort').wallet.address}?apiKey=${this.getApiKey()}`,
if (isNaN(Number(res))) { })
parentEpml.request('showSnackBar', `Failed to Fetch QORT Balance. Try again!`) .then((res) => {
} else { if (isNaN(Number(res))) {
if(this._selectedWallet==coin){//check if we are still fetching wallet balance ... parentEpml.request('showSnackBar', `Failed to Fetch QORT Balance. Try again!`)
this.wallets.get(coin).balance = res } else {
this.balanceString=this.wallets.get(this._selectedWallet).balance+" "+this._selectedWallet.toLocaleUpperCase() if (this._selectedWallet == coin) {
} //check if we are still fetching wallet balance ...
} this.wallets.get(coin).balance = res
}) this.balanceString = this.wallets.get(this._selectedWallet).balance + " " + this._selectedWallet.toLocaleUpperCase()
//fetching the qort transactions }
const txsQort = await parentEpml.request('apiCall', { }
url: `/transactions/search?address=${this.wallets.get('qort').wallet.address}&confirmationStatus=CONFIRMED&reverse=true`, })
}) //fetching the qort transactions
if(this._selectedWallet==coin) const txsQort = await parentEpml.request('apiCall', {
this.wallets.get(coin).transactions = txsQort url: `/transactions/search?address=${this.wallets.get('qort').wallet.address}&confirmationStatus=CONFIRMED&reverse=true`,
})
if (this._selectedWallet == coin)
this.wallets.get(coin).transactions = txsQort
break break
case 'btc': case 'btc':
case 'ltc': case 'ltc':
case 'doge': case 'doge':
//fetching the balance //fetching the balance
const walletName = `${coin}Wallet` const walletName = `${coin}Wallet`
parentEpml parentEpml
.request('apiCall', { .request('apiCall', {
url: `/crosschain/${coin}/walletbalance?apiKey=${this.getApiKey()}`, url: `/crosschain/${coin}/walletbalance?apiKey=${this.getApiKey()}`,
method: 'POST', method: 'POST',
body: `${window.parent.reduxStore.getState().app.selectedAddress[walletName].derivedMasterPublicKey}`, body: `${window.parent.reduxStore.getState().app.selectedAddress[walletName].derivedMasterPublicKey}`,
}) })
.then((res) => { .then((res) => {
if (isNaN(Number(res))) { if (isNaN(Number(res))) {
parentEpml.request('showSnackBar', `Failed to Fetch ${coin.toLocaleUpperCase()} Balance. Try again!`) parentEpml.request('showSnackBar', `Failed to Fetch ${coin.toLocaleUpperCase()} Balance. Try again!`)
} else { } else {
if(this._selectedWallet==coin){//check if we are still fetching wallet balance ... if (this._selectedWallet == coin) {
this.wallets.get(this._selectedWallet).balance = (Number(res) / 1e8).toFixed(8) //check if we are still fetching wallet balance ...
this.balanceString=this.wallets.get(this._selectedWallet).balance+" "+this._selectedWallet.toLocaleUpperCase() this.wallets.get(this._selectedWallet).balance = (Number(res) / 1e8).toFixed(8)
} this.balanceString = this.wallets.get(this._selectedWallet).balance + " " + this._selectedWallet.toLocaleUpperCase()
} }
}) }
//fetching transactions })
const txs = await parentEpml.request('apiCall', { //fetching transactions
url: `/crosschain/${coin}/wallettransactions?apiKey=${this.getApiKey()}`, const txs = await parentEpml.request('apiCall', {
method: 'POST', url: `/crosschain/${coin}/wallettransactions?apiKey=${this.getApiKey()}`,
body: `${window.parent.reduxStore.getState().app.selectedAddress[walletName].derivedMasterPublicKey}`, method: 'POST',
}) body: `${window.parent.reduxStore.getState().app.selectedAddress[walletName].derivedMasterPublicKey}`,
const compareFn = (a, b) => { })
return b.timestamp - a.timestamp const compareFn = (a, b) => {
} return b.timestamp - a.timestamp
const sortedTransactions = txs.sort(compareFn) }
const sortedTransactions = txs.sort(compareFn)
if(this._selectedWallet==coin){ if (this._selectedWallet == coin) {
this.wallets.get(this._selectedWallet).transactions = sortedTransactions this.wallets.get(this._selectedWallet).transactions = sortedTransactions
} }
break break
default: default:
break break
} }
} }
showTransactionDetails(myTransaction, allTransactions) { showTransactionDetails(myTransaction, allTransactions) {
allTransactions.forEach((transaction) => { allTransactions.forEach((transaction) => {
if (myTransaction.signature === transaction.signature) { if (myTransaction.signature === transaction.signature) {
// Do something... // Do something...
let txnFlow = myTransaction.creatorAddress === this.wallets.get('qort').wallet.address ? 'OUT' : 'IN' let txnFlow = myTransaction.creatorAddress === this.wallets.get('qort').wallet.address ? 'OUT' : 'IN'
this.selectedTransaction = { ...transaction, txnFlow } this.selectedTransaction = { ...transaction, txnFlow }
if (this.selectedTransaction.signature.length != 0) { if (this.selectedTransaction.signature.length != 0) {
this.shadowRoot.querySelector('#showTransactionDetailsDialog').show() this.shadowRoot.querySelector('#showTransactionDetailsDialog').show()
} }
} }
}) })
} }
isEmptyArray(arr) { isEmptyArray(arr) {
if (!arr) { if (!arr) {
return true return true
} }
return arr.length === 0 return arr.length === 0
} }
floor(num) { floor(num) {
num = parseFloat(num) num = parseFloat(num)
return isNaN(num) ? 0 : this._format(Math.floor(num)) return isNaN(num) ? 0 : this._format(Math.floor(num))
} }
decimals(num) { decimals(num) {
num = parseFloat(num) // So that conversion to string can get rid of insignificant zeros num = parseFloat(num)
// return isNaN(num) ? 0 : (num + "").split(".")[1] // So that conversion to string can get rid of insignificant zeros
return num % 1 > 0 ? (num + '').split('.')[1] : '0' return num % 1 > 0 ? (num + '').split('.')[1] : '0'
} }
subtract(num1, num2) { subtract(num1, num2) {
return num1 - num2 return num1 - num2
} }
getConfirmations(height, lastBlockHeight) { getConfirmations(height, lastBlockHeight) {
return lastBlockHeight - height + 1 return lastBlockHeight - height + 1
} }
_format(num) { _format(num) {
return num.toLocaleString() return num.toLocaleString()
} }
textColor(color) { textColor(color) {
return color === 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' return color === 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)'
} }
_unconfirmedClass(unconfirmed) { _unconfirmedClass(unconfirmed) {
return unconfirmed ? 'unconfirmed' : '' return unconfirmed ? 'unconfirmed' : ''
} }
} }
window.customElements.define('multi-wallet', MultiWallet) window.customElements.define('multi-wallet', MultiWallet)