import { html, LitElement } from 'lit'
import { render } from 'lit/html.js'
import { repeat } from 'lit/directives/repeat.js'
import { connect } from 'pwa-helpers'
import { store } from '../store'
import { Epml } from '../epml'
import { addPluginRoutes } from '../plugins/addPluginRoutes'
import { setIsOpenDevDialog, setNewTab } from '../redux/app/app-actions'
import { defaultQappsTabs } from '../data/defaultQapps'
import { showPluginStyles, navBarStyles, appAvatarStyles } from '../styles/core-css'
import FileSaver from 'file-saver'
import ShortUniqueId from 'short-unique-id'
import '../functional-components/frag-file-input'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@material/mwc-textfield'
import '@polymer/iron-icons/iron-icons.js'
import '@polymer/paper-dialog/paper-dialog.js'
import '@polymer/paper-icon-button/paper-icon-button.js'
import '@vaadin/grid'
import '@vaadin/text-field'
// Multi language support
import { get, registerTranslateConfig, translate, use } from '../../translate'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
export const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ShowPlugin extends connect(store)(LitElement) {
static get properties() {
return {
app: { type: Object },
pluginConfig: { type: Object },
url: { type: String },
linkParam: { type: String },
registeredUrls: { type: Array },
currentTab: { type: Number },
tabs: { type: Array },
theme: { type: String, reflect: true },
tabInfo: { type: Object },
chatLastSeen: { type: Array },
chatHeads: { type: Array },
proxyPort: { type: Number },
isOpenDevDialog: { type: Boolean }
}
}
static get styles() {
return [showPluginStyles]
}
constructor() {
super()
this.registeredUrls = []
this.initialRegisteredUrls = []
this.currentTab = 0
this.tabs = []
this.uid = new ShortUniqueId()
this.tabInfo = {}
this.chatLastSeen = []
this.chatHeads = []
this.proxyPort = 0
this.isOpenDevDialog = false
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
render() {
const plugSrc = (myPlug) => {
return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}`
}
return html`
${this.tabs.map((tab, index) => {
let title = ''
let icon = ''
let count = 0
if (tab.myPlugObj && tab.myPlugObj.title === "Overview Page") {
title = html`${translate('tabmenu.tm28')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Minting Details") {
title = html`${translate('tabmenu.tm1')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Become a Minter") {
title = html`${translate('tabmenu.tm2')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Sponsorship List") {
title = html`${translate('tabmenu.tm3')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Wallets") {
title = html`${translate('tabmenu.tm4')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Trade Portal") {
title = html`${translate('tabmenu.tm5')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Auto Buy") {
title = html`${translate('tabmenu.tm6')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Reward Share") {
title = html`${translate('tabmenu.tm7')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Q-Chat") {
title = html`${translate('tabmenu.tm8')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Name Registration") {
title = html`${translate('tabmenu.tm9')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Names Market") {
title = html`${translate('tabmenu.tm10')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Websites") {
title = html`${translate('tabmenu.tm11')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Q-Apps") {
title = html`${translate('tabmenu.tm12')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Group Management") {
title = html`${translate('tabmenu.tm13')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Data Management") {
title = html`${translate('tabmenu.tm14')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Puzzles") {
title = html`${translate('tabmenu.tm15')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Node Management") {
title = html`${translate('tabmenu.tm16')}`
} else if (tab.myPlugObj && tab.myPlugObj.title === "Qortal Lottery") {
title = html`${translate('tabmenu.tm42')}`
} else if (tab.myPlugObj && tab.myPlugObj.url === "myapp") {
title = tab.myPlugObj && tab.myPlugObj.title
} else if (tab.myPlugObj && tab.myPlugObj.url === "devmode") {
title = html`${translate('tabmenu.tm38')}`
} else {
title = html`${translate('tabmenu.tm17')}`
}
if (tab.myPlugObj && tab.myPlugObj.mwcicon) {
icon = tab.myPlugObj.mwcicon
} else {
icon = 'tab'
}
if (tab.myPlugObj && (tab.myPlugObj.url === 'myapp') && this.tabInfo[tab.id]) {
title = this.tabInfo[tab.id].name
}
if (tab.myPlugObj && (tab.myPlugObj.url === 'myapp') && this.tabInfo[tab.id]) {
count = this.tabInfo[tab.id].count
}
if (tab.myPlugObj && tab.myPlugObj.url === 'q-chat') {
for (const chat of this.chatHeads) {
const lastReadMessage = this.chatLastSeen.find((ch) => {
let id
if (chat.groupId === 0) {
id = chat.groupId
} else if (chat.groupId) {
id = chat.groupId
} else {
id = chat.address
}
return ch.key.includes(id)
})
if (lastReadMessage && lastReadMessage.timestamp < chat.timestamp) {
count = count + 1
}
}
}
return html`
{
this.currentTab = index
}}"
@mousedown="${(event) => {
if (event.button === 1) {
event.preventDefault();
this.removeTab(index, tab.id);
}
}}"
>
${tab.myPlugObj && tab.myPlugObj.url === "myapp" ?
html`
` : html`
${icon}
`
}
${count ?
html`
${title}
${count}
{ event.stopPropagation(); this.removeTab(index, tab.id)}}>
close
` : html`
${title}
{ event.stopPropagation(); this.removeTab(index, tab.id)}}>
close
`
}
`
})}
${repeat(this.tabs, (tab) => tab.id, (tab, index) =>
html`
this.changePage(val)}
>
`
)}
{
this.shadowRoot.getElementById('domainInput').value = ''
this.shadowRoot.getElementById('portInput').value = ''
this.isOpenDevDialog = false
store.dispatch(setIsOpenDevDialog(false))
}}
>
${translate('tabmenu.tm39')}
${translate("general.close")}
${translate('tabmenu.tm40')}
`
}
firstUpdated() {
this.changeLanguage()
this.tabs.forEach((tab, index) => {
const frame = this.shadowRoot.getElementById(`showPluginFrame${index}`)
this.createEpmlInstance(frame, index)
})
window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage')
const checkTheme = localStorage.getItem('qortalTheme')
use(checkLanguage)
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
})
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
}
}
async getUpdateComplete() {
await super.getUpdateComplete()
return true
}
async getProxyPort() {
this.proxyPort = 0
let framework = ''
const domain = this.shadowRoot.getElementById('domainInput').value
const port = this.shadowRoot.getElementById('portInput').value
if (domain.length >= 3 && port.length >= 2) {
framework = domain + ':' + port
} else {
let errorString = get("tabmenu.tm41")
parentEpml.request('showSnackBar', `${errorString}`)
return
}
let framePort = await parentEpml.request('apiCall', {
url: `/developer/proxy/start`,
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
body: `${framework}`
})
this.createUrl(framePort)
}
createUrl(framePort) {
this.proxyPort = framePort
const myFrameNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const myFrameNodeUrl = myFrameNode.protocol + '://' + myFrameNode.domain + ':' + this.proxyPort
this.changePage({
"url": "devmode",
"domain": "core",
"page": `qdn/browser/index.html?link=${myFrameNodeUrl}&dev=FRAMEWORK`,
"title": "Dev Server",
"icon": "vaadin:desktop",
"mwcicon": "api",
"menus": [],
"parent": false
})
this.shadowRoot.querySelector("#addDevDialog").close()
}
async addTab(tab) {
if (this.tabs == []) {
// ...Nothing to do
} else {
this.tabs.forEach((rac, index) => {
let racId = ''
let tabRacId = ''
let frameRacId = ''
let plugRacId = ''
let iconRacId = ''
racId = rac.id
tabRacId = 'tab-' + racId
frameRacId = 'frame-' + racId
plugRacId = 'plug-' + racId
iconRacId = 'icon-' + racId
const plugObjRac = rac.url
var tabActiveRac = this.shadowRoot.getElementById(tabRacId)
var frameActiveRac = this.shadowRoot.getElementById(frameRacId)
var plugActiveRac = this.shadowRoot.getElementById(plugRacId)
var iconActiveRac = this.shadowRoot.getElementById(iconRacId)
if (plugObjRac === undefined || '') {
tabActiveRac.classList.remove('active')
iconActiveRac.classList.remove('iconActive')
iconActiveRac.classList.add('iconInactive')
plugActiveRac.classList.remove('showIframe')
plugActiveRac.classList.add('hideIframe')
} else {
tabActiveRac.classList.remove('active')
iconActiveRac.classList.remove('iconActive')
iconActiveRac.classList.add('iconInactive')
frameActiveRac.classList.remove('showIframe')
frameActiveRac.classList.add('hideIframe')
}
})
}
this.tabs = [...this.tabs, tab]
await this.getUpdateComplete()
// add the new tab to the tabs array
const newIndex = this.tabs.length - 1
// render the tab and wait for it to be added to the DOM
const frame = this.shadowRoot.getElementById(`showPluginFrame${newIndex}`)
this.createEpmlInstance(frame, newIndex)
}
removeTab(index, tabA) {
const tabB = this.tabs.length - 1
const tabC = this.tabs[tabB].id
if (tabC === tabA) {
let theId = ''
let tabId = ''
let frameId = ''
let plugId = ''
let iconId = ''
this.tabs = this.tabs.filter((tab, tIndex) => tIndex !== index)
this.currentTab = this.tabs.length - 1
const tabD = this.tabs.length - 1
if (tabD < 0) {
const lengthOfTabs = this.tabs.length
this.addTab({
url: '',
id: this.uid.rnd()
})
this.currentTab = lengthOfTabs
} else {
const plugObj = this.tabs[tabD].url
theId = this.tabs[tabD].id
tabId = 'tab-' + theId
frameId = 'frame-' + theId
plugId = 'plug-' + theId
iconId = 'icon-' + theId
var tabActive = this.shadowRoot.getElementById(tabId)
var frameActive = this.shadowRoot.getElementById(frameId)
var plugActive = this.shadowRoot.getElementById(plugId)
var iconActive = this.shadowRoot.getElementById(iconId)
if (plugObj === undefined || '') {
tabActive.classList.add('active')
iconActive.classList.remove('iconInactive')
iconActive.classList.add('iconActive')
plugActive.classList.remove('hideIframe')
plugActive.classList.add('showIframe')
} else {
tabActive.classList.add('active')
iconActive.classList.remove('iconInactive')
iconActive.classList.add('iconActive')
frameActive.classList.remove('hideIframe')
frameActive.classList.add('showIframe')
}
this.requestUpdate()
}
} else {
// Remove tab from array
this.tabs = this.tabs.filter((tab, tIndex) => tIndex !== index)
if (this.tabs.length !== 0) {
this.currentTab = 0
}
this.requestUpdate()
}
}
createEpmlInstance(frame, index) {
const showingPluginEpml = new Epml({
type: 'WINDOW',
source: frame.contentWindow
})
addPluginRoutes(showingPluginEpml)
showingPluginEpml.imReady()
// store Epml instance in tab for later use
this.tabs[index].epmlInstance = showingPluginEpml
// Register each instance with a unique identifier
Epml.registerProxyInstance(`visible-plugin-${index}`, showingPluginEpml)
}
updated(changedProps) {
if (changedProps.has('url') || changedProps.has('registeredUrls')) {
const plugArr = []
this.registeredUrls.forEach(myPlugArr => {
myPlugArr.menus.length === 0 ? plugArr.push(myPlugArr) : myPlugArr.menus.forEach(i => plugArr.push(myPlugArr, i))
})
const myPlugObj = plugArr.find(pagePlug => {
return pagePlug.url === this.url
})
if (this.tabs.length === 0) {
this.addTab({
url: '',
id: this.uid.rnd()
})
} else {
const copiedTabs = [...this.tabs]
copiedTabs[this.currentTab] = {
...copiedTabs[this.currentTab],
url: this.url,
myPlugObj
}
this.tabs = copiedTabs
}
this.requestUpdate()
}
if (changedProps.has('computerUrl')) {
if (this.computedUrl !== 'about:blank') {
this.loading = true
}
}
}
changePage(page) {
const copiedTabs = [...this.tabs]
copiedTabs[this.currentTab] = {
...copiedTabs[this.currentTab],
myPlugObj: page,
url: page.url
}
this.tabs = copiedTabs
}
async stateChanged(state) {
const split = state.app.url.split('/')
const newRegisteredUrls = state.app.registeredUrls
let newUrl, newLinkParam
if (newRegisteredUrls !== this.registeredUrls) {
this.registeredUrls = newRegisteredUrls
}
if (split[0] === '' && split[1] === 'app' && split[2] === undefined) {
newUrl = ''
newLinkParam = ''
} else if (split.length === 5 && split[1] === 'app') {
newUrl = split[2]
newLinkParam = split[3] === undefined ? '' : '?' + split[3] + '/' + split[4]
} else if (split[1] === 'app') {
newUrl = split[2]
newLinkParam = ''
} else {
newUrl = '404'
newLinkParam = ''
}
if (newUrl !== this.url) {
this.url = newUrl
}
if (newLinkParam !== this.linkParam) {
this.linkParam = newLinkParam
}
if (this.tabInfo !== state.app.tabInfo) {
this.tabInfo = state.app.tabInfo
}
if (this.chatLastSeen !== state.app.chatLastSeen) {
this.chatLastSeen = state.app.chatLastSeen
}
if (state.app.chatHeads !== this.unModifiedChatHeads) {
let chatHeads = []
if (state.app.chatHeads && state.app.chatHeads.groups) {
chatHeads = [...chatHeads, ...state.app.chatHeads.groups]
}
if (state.app.chatHeads && state.app.chatHeads.direct) {
chatHeads = [...chatHeads, ...state.app.chatHeads.direct]
}
this.chatHeads = chatHeads
this.unModifiedChatHeads = state.app.chatHeads
}
if (state.app.newTab) {
const newTab = state.app.newTab
if (newTab.openExisting && this.tabs.find((tab) => tab.url === newTab.url)) {
const findIndex = this.tabs.findIndex((tab) => tab.url === newTab.url)
if (findIndex !== -1) {
this.currentTab = findIndex
}
store.dispatch(setNewTab(null))
} else if (!this.tabs.find((tab) => tab.id === newTab.id)) {
await this.addTab(newTab)
this.currentTab = this.tabs.length - 1
//clear newTab
store.dispatch(setNewTab(null))
} else {
const findIndex = this.tabs.findIndex((tab) => tab.id === newTab.id)
if (findIndex !== -1) {
const copiedTabs = [...this.tabs]
copiedTabs[findIndex] = newTab
this.tabs = copiedTabs
this.currentTab = findIndex
}
//clear newTab
store.dispatch(setNewTab(null))
}
}
if (state.app.isOpenDevDialog) {
this.isOpenDevDialog = state.app.isOpenDevDialog
}
}
}
window.customElements.define('show-plugin', ShowPlugin)
class NavBar extends connect(store)(LitElement) {
static get properties() {
return {
menuList: { type: Array },
newMenuList: { type: Array },
myMenuList: { type: Array },
myMenuPlugins: { type: Array },
myApps: { type: Array },
changePage: { attribute: false },
pluginName: { type: String },
pluginType: { type: String },
pluginPage: { type: String },
mwcIcon: { type: String },
pluginNameToDelete: { type: String },
pluginNumberToDelete: { type: String },
textFieldDisabled: { type: Boolean },
initialName: { type: String },
newId: { type: String },
removeTitle: { type: String },
myFollowedNames: { type: Array },
myFollowedNamesList: { type: Array },
searchNameContentString: { type: String },
searchNameResources: { type: Array },
addressInfo: { type: Object }
}
}
static get styles() {
return [navBarStyles]
}
constructor() {
super()
this.menuList = []
this.newMenuList = []
this.myMenuList = []
this.myMenuPlugins = []
this.pluginName = ''
this.pluginType = ''
this.pluginPage = ''
this.myApps = ''
this.mwcIcon = ''
this.pluginNameToDelete = ''
this.pluginNumberToDelete = ''
this.textFieldDisabled = false
this.initialName = ''
this.newId = ''
this.removeTitle = ''
this.myFollowedNames = []
this.myFollowedNamesList = []
this.searchContentString = ''
this.searchNameResources = []
this.addressInfo = store.getState().app.accountInfo.addressInfo
this._updateMyMenuPlugins = this._updateMyMenuPlugins.bind(this)
}
render() {
return html`
this.resetMenu()}" title="${translate("tabmenu.tm29")}">reset_tv
this.openNameSearch()}" title="${translate("tabmenu.tm30")}">person_search
this.openImportDialog()}" title="${translate("tabmenu.tm33")}">upload
this.exportTabMenu()}" title="${translate("tabmenu.tm34")}">download
${repeat(this.myMenuList, (plugin) => plugin.url, (plugin, index) => html`
${this.renderRemoveIcon(plugin.url, plugin.mwcicon, plugin.title, plugin.pluginNumber, plugin)}
${this.renderTitle(plugin.url, plugin.title)}
`)}
this.openAddNewPlugin()}">
${translate("tabmenu.tm19")}
${translate("tabmenu.tm26")}
${translate("tabmenu.tm24")}
${translate("tabmenu.tm19")}
${translate("general.close")}
${translate("tabmenu.tm27")}
${translate("tabmenu.tm23")}
${this.removeTitle}
${translate("general.yes")}
${translate("general.no")}
this.searchNameResult()}" title="${translate("websitespage.schange35")}">
this.closeNameSearch()}" title="${translate("general.close")}">
{
render(html`${this.renderNameAvatar(data.item)}`, root)
}}
>
{
render(html`${data.item.name}`, root)
}}
>
{
render(html`${this.renderMyFollowUnfollowButton(data.item)}`, root)
}}
>
${this.isEmptyArray(this.searchNameResources) ? html`
${translate("login.entername")}
`: ''}
${translate("tabmenu.tm31")}
{
render(html`${this.renderNameAvatar(data.item)}`, root)
}}
>
{
render(html`${data.item.name}`, root)
}}
>
{
render(html`${this.renderMyFollowUnfollowButton(data.item)}`, root)
}}
>
${this.isEmptyArray(this.myFollowedNamesList) ? html`
${translate("tabmenu.tm32")}
`: ''}
`
}
async firstUpdated() {
addPluginRoutes(parentEpml)
parentEpml.imReady()
this.addressInfo = store.getState().app.accountInfo.addressInfo
this.menuList = store.getState().app.registeredUrls
const addressInfo = this.addressInfo
const isMinter = addressInfo?.error !== 124 && +addressInfo?.level > 0
const isSponsor = +addressInfo?.level >= 5
const appDelay = ms => new Promise(res => setTimeout(res, ms))
await this.checkMyMenuPlugins()
await appDelay(250)
if (!isMinter) {
this.newMenuList = this.myMenuPlugins.filter((minter) => {
return minter.url !== 'minting'
})
} else {
this.newMenuList = this.myMenuPlugins.filter((minter) => {
return minter.url !== 'become-minter'
})
}
if (!isSponsor) {
this.myMenuList = this.newMenuList.filter((sponsor) => {
return sponsor.url !== 'sponsorship-list'
})
} else {
this.myMenuList = this.newMenuList
}
await appDelay(250)
await this.getMyFollowedNames()
await this.getMyFollowedNamesList()
}
async _updateMyMenuPlugins(event) {
await new Promise((res) => {
setTimeout(() => {
res()
}, 500)
})
this.myMenuPlugins = event.detail
const addressInfo = this.addressInfo
const isMinter = addressInfo?.error !== 124 && +addressInfo?.level > 0
const isSponsor = +addressInfo?.level >= 5
if (!isMinter) {
this.newMenuList = this.myMenuPlugins.filter((minter) => {
return minter.url !== 'minting'
})
} else {
this.newMenuList = this.myMenuPlugins.filter((minter) => {
return minter.url !== 'become-minter'
})
}
if (!isSponsor) {
this.myMenuList = this.newMenuList.filter((sponsor) => {
return sponsor.url !== 'sponsorship-list'
})
} else {
this.myMenuList = this.newMenuList
}
this.requestUpdate()
}
connectedCallback() {
super.connectedCallback()
window.addEventListener('myMenuPlugs-event', this._updateMyMenuPlugins)
}
disconnectedCallback() {
window.removeEventListener('myMenuPlugs-event', this._updateMyMenuPlugins)
super.disconnectedCallback()
}
openImportDialog() {
this.shadowRoot.getElementById('importTabMenutDialog').show()
}
importTabMenu(file) {
let myFile = ''
myFile = file
this.myMenuPlugins = []
localStorage.removeItem('myMenuPlugs')
const newTabMenu = JSON.parse((myFile) || '[]')
const copyPayload = [...newTabMenu]
localStorage.setItem('myMenuPlugs', JSON.stringify(newTabMenu))
this.saveSettingToTemp(copyPayload)
this.shadowRoot.getElementById('importTabMenutDialog').close()
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
this.firstUpdated()
let success5string = get('tabmenu.tm36')
parentEpml.request('showSnackBar', `${success5string}`)
}
exportTabMenu() {
let tabMenu = ''
const qortalTabMenu = JSON.stringify(localStorage.getItem('myMenuPlugs'))
const qortalTabMenuSave = JSON.parse((qortalTabMenu) || '[]')
const blob = new Blob([qortalTabMenuSave], { type: 'text/plain;charset=utf-8' })
tabMenu = 'qortal.tabmenu'
this.saveFileToDisk(blob, tabMenu)
}
async saveFileToDisk(blob, fileName) {
try {
const fileHandle = await self.showSaveFilePicker({
suggestedName: fileName,
types: [{
description: 'File'
}]
})
const writeFile = async (fileHandle, contents) => {
const writable = await fileHandle.createWritable()
await writable.write(contents)
await writable.close()
}
writeFile(fileHandle, blob).then(() => console.log('FILE SAVED'))
let snack4string = get('tabmenu.tm37')
parentEpml.request('showSnackBar', `${snack4string} ${fileName}`)
} catch (error) {
if (error.name === 'AbortError') {
return
}
FileSaver.saveAs(blob, fileName)
let snack4string = get('tabmenu.tm37')
parentEpml.request('showSnackBar', `${snack4string} ${fileName}`)
}
}
openNameSearch() {
this.searchNameResources = []
this.shadowRoot.getElementById('searchNameContent').value = ''
this.shadowRoot.getElementById('myFollowedNamesDialog').close()
this.shadowRoot.getElementById('searchNameDialog').open()
}
closeNameSearch() {
this.shadowRoot.getElementById('searchNameDialog').close()
}
openMyFollowedNames() {
this.shadowRoot.getElementById('searchNameDialog').close()
this.shadowRoot.getElementById('myFollowedNamesDialog').open()
this.getMyFollowedNamesList()
}
closeMyFollowedNames() {
this.shadowRoot.getElementById('myFollowedNamesDialog').close()
}
async getMyFollowedNames() {
this.myFollowedNames = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`
})
}
searchNameKeyListener(e) {
if (e.key === 'Enter') {
this.searchNameResult()
}
}
async getMyFollowedNamesList() {
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const myNodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const followedNamesUrl = `${myNodeUrl}/lists/followedNames?apiKey=${this.getApiKey()}`
var myFollowedNamesNew = []
this.myFollowedNamesList = []
await fetch(followedNamesUrl).then(response => {
return response.json()
}).then(data => {
return data.map(item => {
const addListName = {
name: item
}
myFollowedNamesNew.push(addListName)
})
})
this.myFollowedNamesList = myFollowedNamesNew
if (this.shadowRoot.getElementById('myFollowedNamesDialog').opened) {
this.shadowRoot.getElementById('myFollowedNamesDialog').notifyResize()
}
}
async searchNameResult() {
let searchMyName = this.shadowRoot.getElementById('searchNameContent').value
if (searchMyName.length === 0) {
let err1string = get('appspage.schange34')
parentEpml.request('showSnackBar', `${err1string}`)
} else {
let searchNameResources = await parentEpml.request('apiCall', {
url: `/names/search?query=${searchMyName}&prefix=true&limit=0&reverse=true`
})
if (this.isEmptyArray(searchNameResources)) {
let err2string = get('appspage.schange17')
parentEpml.request('showSnackBar', `${err2string}`)
} else {
this.searchNameResources = searchNameResources
if (this.shadowRoot.getElementById('searchNameDialog').opened) {
this.shadowRoot.getElementById('searchNameDialog').notifyResize()
}
}
}
}
renderNameAvatar(nameObj) {
let myName = nameObj.name
const myNameNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const myNameNodeUrl = myNameNode.protocol + '://' + myNameNode.domain + ':' + myNameNode.port
const nameUrl = `${myNameNodeUrl}/arbitrary/THUMBNAIL/${myName}/qortal_avatar?async=true`
return html`
`
}
renderMyFollowUnfollowButton(nameObj) {
let name = nameObj.name
if (this.myFollowedNames == null || !Array.isArray(this.myFollowedNames)) {
return html``
}
if (this.myFollowedNames.indexOf(name) === -1) {
return html` this.myFollowName(nameObj)}>add_to_queue ${translate("appspage.schange29")}`
} else {
return html` this.myUnfollowName(nameObj)}>remove_from_queue ${translate("appspage.schange30")}`
}
}
async myFollowName(nameObj) {
let name = nameObj.name
let items = [
name
]
let namesJsonString = JSON.stringify({ 'items': items })
let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: `${namesJsonString}`
})
if (ret === true) {
this.myFollowedNames = this.myFollowedNames.filter(item => item != name)
this.myFollowedNames.push(name)
} else {
let err3string = get('appspage.schange22')
parentEpml.request('showSnackBar', `${err3string}`)
}
await this.getMyFollowedNamesList()
return ret
}
async myUnfollowName(nameObj) {
let name = nameObj.name
let items = [
name
]
let namesJsonString = JSON.stringify({ 'items': items })
let ret = await parentEpml.request('apiCall', {
url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: `${namesJsonString}`
})
if (ret === true) {
this.myFollowedNames = this.myFollowedNames.filter(item => item != name)
} else {
let err4string = get('appspage.schange23')
parentEpml.request('showSnackBar', `${err4string}`)
}
await this.getMyFollowedNamesList()
return ret
}
async checkMyMenuPlugins() {
const appDelay = ms => new Promise(res => setTimeout(res, ms))
if (localStorage.getItem('myMenuPlugs') === null) {
await appDelay(500)
const listOfPlugins = this.menuList.filter(plugin => plugin.url !== 'puzzles')
const addQapps = [...listOfPlugins, ...defaultQappsTabs]
const myObj = JSON.stringify(addQapps)
localStorage.setItem('myMenuPlugs', myObj)
await appDelay(250)
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
} else {
let newPluginMenu = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
const oldQchat = 'messaging/q-chat/index.html'
const newQchat = 'q-chat/index.html'
const oldMinting = 'minting/index.html'
const newMinting = 'minting-info/index.html'
const oldWebsites = 'qdn/index.html'
const newWebsites = 'q-website/index.html'
const oldDatamanager = 'qdn/data-management/index.html'
const newDatamanager = 'data-management/index.html'
// Check if local storage have broken links and replace them
newPluginMenu.find(a => {
if (a.page === oldQchat) {
a.page = newQchat
} else if (a.page === oldMinting) {
a.page = newMinting
} else if (a.page === oldWebsites) {
a.page = newWebsites
} else if (a.page === oldDatamanager) {
a.page = newDatamanager
} else {}
})
localStorage.setItem('myMenuPlugs', JSON.stringify(newPluginMenu))
await appDelay(250)
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
}
}
resetMenu() {
localStorage.removeItem('myMenuPlugs')
this.firstUpdated()
}
val() {
const theValue = this.shadowRoot.getElementById('pluginTypeInput').value
if (theValue === 'reject') {
this.textFieldDisabled = false
this.initialName = ''
this.mwcIcon = ''
} else if (theValue === '0') {
this.textFieldDisabled = false
this.initialName = ''
this.mwcIcon = ''
} else if (theValue === '1') {
this.textFieldDisabled = false
this.initialName = ''
this.mwcIcon = ''
} else if (theValue === 'overview-page') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Overview Page'
this.mwcIcon = 'home'
} else if (theValue === 'minting') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Minting Details'
this.mwcIcon = 'info_outline'
} else if (theValue === 'become-minter') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Become a Minter'
this.mwcIcon = 'thumb_up'
} else if (theValue === 'sponsorship-list') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Sponsorship List'
this.mwcIcon = 'format_list_numbered'
} else if (theValue === 'wallet') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Wallets'
this.mwcIcon = 'account_balance_wallet'
} else if (theValue === 'trade-portal') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Trade Portal'
this.mwcIcon = 'format_list_bulleted'
} else if (theValue === 'trade-bot-portal') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Auto Buy'
this.mwcIcon = 'shop'
} else if (theValue === 'reward-share') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Reward Share'
this.mwcIcon = 'ios_share'
} else if (theValue === 'q-chat') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Q-Chat'
this.mwcIcon = 'forum'
} else if (theValue === 'name-registration') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Name Registration'
this.mwcIcon = 'manage_accounts'
} else if (theValue === 'names-market') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Names Market'
this.mwcIcon = 'store'
} else if (theValue === 'websites') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Websites'
this.mwcIcon = 'desktop_mac'
} else if (theValue === 'qapps') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Q-Apps'
this.mwcIcon = 'apps'
} else if (theValue === 'group-management') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Group Management'
this.mwcIcon = 'group'
} else if (theValue === 'data-management') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Data Management'
this.mwcIcon = 'storage'
} else if (theValue === 'puzzles') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Puzzles'
this.mwcIcon = 'extension'
} else if (theValue === 'node-management') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Node Management'
this.mwcIcon = 'cloud'
} else if (theValue === 'lottery') {
this.mwcIcon = ''
this.initialName = ''
this.textFieldDisabled = true
this.initialName = 'Qortal Lottery'
this.mwcIcon = 'token'
}
}
filterSelectMenu() {
const addressInfoSelect = this.addressInfo
const isMinterSelect = addressInfoSelect?.error !== 124 && +addressInfoSelect?.level > 0
const isSponsorSelect = +addressInfoSelect?.level >= 5
if (!isMinterSelect) {
return html`
`
} else if (isMinterSelect && isSponsorSelect) {
return html`
`
} else {
return html`
`
}
}
openAddNewPlugin() {
this.shadowRoot.getElementById('pluginTypeInput').value = 'reject'
this.shadowRoot.getElementById('pluginNameInput').value = ''
this.initialName = ''
this.textFieldDisabled = false
this.shadowRoot.querySelector('#addNewPlugin').show()
}
async addToMyMenuPlugins() {
this.newId = ''
const newUid = new ShortUniqueId({ length: 10 })
this.newId = 'plugin-' + newUid.rnd()
this.pluginType = this.shadowRoot.getElementById('pluginTypeInput').value
if (this.pluginType === 'reject') {
let myplugerr = get('tabmenu.tm25')
parentEpml.request('showSnackBar', `${myplugerr}`)
return false
} else if (this.pluginType === '0') {
this.mwcIcon = ''
this.pluginName = this.shadowRoot.getElementById('pluginNameInput').value
if (this.pluginName === 'Q-Blog') {
this.mwcIcon = 'rss_feed'
} else if (this.pluginName === 'Q-Mail') {
this.mwcIcon = 'mail'
} else {
this.mwcIcon = 'apps'
}
var oldMenuPlugs = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
const newMenuPlugsItem = {
'url': 'myapp',
'domain': 'core',
'page': `qdn/browser/index.html?name=${this.pluginName}&service=APP`,
'title': this.pluginName,
'icon': 'vaadin:external-browser',
'mwcicon': this.mwcIcon,
'pluginNumber': this.newId,
'menus': [],
'parent': false
}
const validatePluginName = async () => {
if (this.pluginType === '0' && this.pluginName.length == 0) {
let myplugstring1 = get('walletpage.wchange50')
parentEpml.request('showSnackBar', `${myplugstring1}`)
return false
}
let myPluginName = false
this.myPluginNameRes = []
await parentEpml.request('apiCall', {
url: `/arbitrary/resources/search?service=APP&query=${this.pluginName}&exactmatchnames=true&limit=1`
}).then(res => {
this.myPluginNameRes = res
})
myPluginName = !(this.myPluginNameRes === undefined || this.myPluginNameRes.length == 0)
return myPluginName
}
let myNameRes = await validatePluginName()
if (myNameRes !== false) {
oldMenuPlugs.push(newMenuPlugsItem)
const copyPayload = [...oldMenuPlugs]
localStorage.setItem('myMenuPlugs', JSON.stringify(oldMenuPlugs))
this.saveSettingToTemp(copyPayload)
let myplugstring2 = get('walletpage.wchange52')
parentEpml.request('showSnackBar', `${myplugstring2}`)
this.closeAddNewPlugin()
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
this.firstUpdated()
} else {
let myplugstring3 = get('websitespage.schange17')
parentEpml.request('showSnackBar', `${myplugstring3}`)
return false
}
} else if (this.pluginType === '1') {
this.mwcIcon = ''
this.pluginName = this.shadowRoot.getElementById('pluginNameInput').value
this.mwcIcon = 'web'
var oldMenuPlugs = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
const newMenuPlugsItem = {
'url': 'myapp',
'domain': 'core',
'page': `qdn/browser/index.html?name=${this.pluginName}&service=WEBSITE`,
'title': this.pluginName,
'icon': 'vaadin:external-browser',
'mwcicon': this.mwcIcon,
'pluginNumber': this.newId,
'menus': [],
'parent': false
}
const validatePluginName = async () => {
if (this.pluginType === '1' && this.pluginName.length == 0) {
let myplugstring1 = get('walletpage.wchange50')
parentEpml.request('showSnackBar', `${myplugstring1}`)
return false
}
let myPluginName = false
this.myPluginNameRes = []
await parentEpml.request('apiCall', {
url: `/arbitrary/resources/search?service=WEBSITE&query=${this.pluginName}&exactmatchnames=true&limit=1`
}).then(res => {
this.myPluginNameRes = res
})
myPluginName = !(this.myPluginNameRes === undefined || this.myPluginNameRes.length == 0)
return myPluginName
}
let myNameRes = await validatePluginName()
if (myNameRes !== false) {
oldMenuPlugs.push(newMenuPlugsItem)
const copyPayload = [...oldMenuPlugs]
localStorage.setItem('myMenuPlugs', JSON.stringify(oldMenuPlugs))
this.saveSettingToTemp(copyPayload)
let myplugstring2 = get('walletpage.wchange52')
parentEpml.request('showSnackBar', `${myplugstring2}`)
this.closeAddNewPlugin()
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
this.firstUpdated()
} else {
let myplugstring3 = get('websitespage.schange17')
parentEpml.request('showSnackBar', `${myplugstring3}`)
return false
}
} else {
this.pluginPage = ''
if (this.pluginType === 'overview-page') {
this.pluginPage = 'overview-page/index.html'
} else if (this.pluginType === 'minting') {
this.pluginPage = 'minting-info/index.html'
} else if (this.pluginType === 'become-minter') {
this.pluginPage = 'become-minter/index.html'
} else if (this.pluginType === 'sponsorship-list') {
this.pluginPage = 'sponsorship-list/index.html'
} else if (this.pluginType === 'wallet') {
this.pluginPage = 'wallet/index.html'
} else if (this.pluginType === 'trade-portal') {
this.pluginPage = 'trade-portal/index.html'
} else if (this.pluginType === 'trade-bot-portal') {
this.pluginPage = 'trade-bot/index.html'
} else if (this.pluginType === 'reward-share') {
this.pluginPage = 'reward-share/index.html'
} else if (this.pluginType === 'q-chat') {
this.pluginPage = 'q-chat/index.html'
} else if (this.pluginType === 'name-registration') {
this.pluginPage = 'name-registration/index.html'
} else if (this.pluginType === 'names-market') {
this.pluginPage = 'names-market/index.html'
} else if (this.pluginType === 'websites') {
this.pluginPage = 'q-website/index.html'
} else if (this.pluginType === 'qapps') {
this.pluginPage = 'q-app/index.html'
} else if (this.pluginType === 'group-management') {
this.pluginPage = 'group-management/index.html'
} else if (this.pluginType === 'data-management') {
this.pluginPage = 'data-management/index.html'
} else if (this.pluginType === 'puzzles') {
this.pluginPage = 'puzzles/index.html'
} else if (this.pluginType === 'node-management') {
this.pluginPage = 'node-management/index.html'
} else if (this.pluginType === 'lottery') {
this.pluginPage = 'qortal-lottery/index.html'
}
var oldMenuPlugs = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
const newMenuPlugsItem = {
'url': this.pluginType,
'domain': 'core',
'page': this.pluginPage,
'title': this.initialName,
'icon': 'vaadin:external-browser',
'mwcicon': this.mwcIcon,
'pluginNumber': this.newId,
'menus': [],
'parent': false
}
oldMenuPlugs.push(newMenuPlugsItem)
const copyPayload = [...oldMenuPlugs]
localStorage.setItem('myMenuPlugs', JSON.stringify(oldMenuPlugs))
this.saveSettingToTemp(copyPayload)
let myplugstring2 = get('walletpage.wchange52')
parentEpml.request('showSnackBar', `${myplugstring2}`)
this.closeAddNewPlugin()
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
this.firstUpdated()
}
}
closeAddNewPlugin() {
this.shadowRoot.querySelector('#addNewPlugin').close()
this.shadowRoot.getElementById('pluginTypeInput').value = 'reject'
this.shadowRoot.getElementById('pluginNameInput').value = ''
this.initialName = ''
this.textFieldDisabled = false
}
renderTitle(theUrl, theName) {
if (theUrl === 'overview-page') {
return html`${translate('tabmenu.tm28')}`
} else if (theUrl === 'minting') {
return html`${translate('tabmenu.tm1')}`
} else if (theUrl === 'become-minter') {
return html`${translate('tabmenu.tm2')}`
} else if (theUrl === 'sponsorship-list') {
return html`${translate('tabmenu.tm3')}`
} else if (theUrl === 'wallet') {
return html`${translate('tabmenu.tm4')}`
} else if (theUrl === 'trade-portal') {
return html`${translate('tabmenu.tm5')}`
} else if (theUrl === 'trade-bot-portal') {
return html`${translate('tabmenu.tm6')}`
} else if (theUrl === 'reward-share') {
return html`${translate('tabmenu.tm7')}`
} else if (theUrl === 'q-chat') {
return html`${translate('tabmenu.tm8')}`
} else if (theUrl === 'name-registration') {
return html`${translate('tabmenu.tm9')}`
} else if (theUrl === 'names-market') {
return html`${translate('tabmenu.tm10')}`
} else if (theUrl === 'websites') {
return html`${translate('tabmenu.tm11')}`
} else if (theUrl === 'qapps') {
return html`${translate('tabmenu.tm12')}`
} else if (theUrl === 'group-management') {
return html`${translate('tabmenu.tm13')}`
} else if (theUrl === 'data-management') {
return html`${translate('tabmenu.tm14')}`
} else if (theUrl === 'puzzles') {
return html`${translate('tabmenu.tm15')}`
} else if (theUrl === 'node-management') {
return html`${translate('tabmenu.tm16')}`
} else if (theUrl === 'lottery') {
return html`${translate('tabmenu.tm42')}`
} else {
return html`${theName}`
}
}
renderRemoveIcon(appurl, appicon, appname, appid, appplugin) {
return html`
`
}
openRemoveApp(pluginNameTD, pluginNumberTD, pluginUrlTD) {
this.pluginNameToDelete = ''
this.pluginNameToDelete = pluginNameTD
this.pluginNumberToDelete = ''
this.pluginNumberToDelete = pluginNumberTD
this.removeTitle = ''
if (pluginUrlTD === 'overview-page') {
this.removeTitle = html`${translate('tabmenu.tm28')}`
} else if (pluginUrlTD === 'minting') {
this.removeTitle = html`${translate('tabmenu.tm1')}`
} else if (pluginUrlTD === 'become-minter') {
this.removeTitle = html`${translate('tabmenu.tm2')}`
} else if (pluginUrlTD === 'sponsorship-list') {
this.removeTitle = html`${translate('tabmenu.tm3')}`
} else if (pluginUrlTD === 'wallet') {
this.removeTitle = html`${translate('tabmenu.tm4')}`
} else if (pluginUrlTD === 'trade-portal') {
this.removeTitle = html`${translate('tabmenu.tm5')}`
} else if (pluginUrlTD === 'trade-bot-portal') {
this.removeTitle = html`${translate('tabmenu.tm6')}`
} else if (pluginUrlTD === 'reward-share') {
this.removeTitle = html`${translate('tabmenu.tm7')}`
} else if (pluginUrlTD === 'q-chat') {
this.removeTitle = html`${translate('tabmenu.tm8')}`
} else if (pluginUrlTD === 'name-registration') {
this.removeTitle = html`${translate('tabmenu.tm9')}`
} else if (pluginUrlTD === 'names-market') {
this.removeTitle = html`${translate('tabmenu.tm10')}`
} else if (pluginUrlTD === 'websites') {
this.removeTitle = html`${translate('tabmenu.tm11')}`
} else if (pluginUrlTD === 'qapps') {
this.removeTitle = html`${translate('tabmenu.tm12')}`
} else if (pluginUrlTD === 'group-management') {
this.removeTitle = html`${translate('tabmenu.tm13')}`
} else if (pluginUrlTD === 'data-management') {
this.removeTitle = html`${translate('tabmenu.tm14')}`
} else if (pluginUrlTD === 'puzzles') {
this.removeTitle = html`${translate('tabmenu.tm15')}`
} else if (pluginUrlTD === 'node-management') {
this.removeTitle = html`${translate('tabmenu.tm16')}`
} else if (pluginUrlTD === 'lottery') {
this.removeTitle = html`${translate('tabmenu.tm42')}`
} else {
this.removeTitle = html`${pluginNameTD}`
}
this.shadowRoot.querySelector('#removePlugin').show()
}
removeAppFromArray() {
const pluginToRemove = this.pluginNumberToDelete
this.newMenuFilter = []
this.newMenuFilter = this.myMenuList.filter((item) => item.pluginNumber !== pluginToRemove)
const copyPayload = [...this.newMenuFilter]
const myNewObj = JSON.stringify(this.newMenuFilter)
localStorage.removeItem('myMenuPlugs')
localStorage.setItem('myMenuPlugs', myNewObj)
this.saveSettingToTemp(copyPayload)
this.myMenuPlugins = JSON.parse(localStorage.getItem('myMenuPlugs') || '[]')
this.firstUpdated()
this.closeRemoveApp()
}
saveSettingToTemp(data) {
const tempSettingsData = JSON.parse(localStorage.getItem('temp-settings-data') || '{}')
const newTemp = {
...tempSettingsData,
myMenuPlugs: {
data: data,
timestamp: Date.now()
}
}
localStorage.setItem('temp-settings-data', JSON.stringify(newTemp))
this.dispatchEvent(
new CustomEvent('temp-settings-data-event', {
bubbles: true,
composed: true
})
)
}
closeRemoveApp() {
this.shadowRoot.querySelector('#removePlugin').close()
this.pluginNameToDelete = ''
this.pluginNumberToDelete = ''
}
async extractComponents(url) {
if (!url.startsWith('qortal://')) {
return null
}
url = url.replace(/^(qortal\:\/\/)/, '')
if (url.includes('/')) {
let parts = url.split('/')
const service = parts[0].toUpperCase()
parts.shift()
const name = parts[0]
parts.shift()
let identifier
if (parts.length > 0) {
// Do not shift yet
identifier = parts[0]
// Check if a resource exists with this service, name and identifier combination
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const url = `${nodeUrl}/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${myNode.apiKey}}`
const res = await fetch(url)
const data = await res.json()
if (data.totalChunkCount > 0) {
// Identifier exists, so don't include it in the path
parts.shift()
} else {
identifier = null
}
}
const path = parts.join('/')
const components = {}
components['service'] = service
components['name'] = name
components['identifier'] = identifier
components['path'] = path
return components
}
return null
}
async getQuery(value) {
let newQuery = value
if (newQuery.endsWith('/')) {
newQuery = newQuery.slice(0, -1)
}
const res = await this.extractComponents(newQuery)
if (!res) return
const { service, name, identifier, path } = res
let query = `?service=${service}`
if (name) {
query = query + `&name=${name}`
}
if (identifier) {
query = query + `&identifier=${identifier}`
}
if (path) {
query = query + `&path=${path}`
}
if (service === 'APP') {
this.changePage({
'url': 'myapp',
'domain': 'core',
'page': `qdn/browser/index.html${query}`,
'title': name || 'Q-App',
'icon': 'vaadin:external-browser',
'mwcicon': 'open_in_browser',
'menus': [],
'parent': false
})
} else if (service === 'WEBSITE') {
this.changePage({
'url': 'myapp',
'domain': 'core',
'page': `qdn/browser/index.html${query}`,
'title': name || 'Website',
'icon': 'vaadin:desktop',
'mwcicon': 'desktop_mac',
'menus': [],
'parent': false
})
}
}
async handlePasteLink(e) {
try {
const value = this.shadowRoot.getElementById('linkInput').value
await this.getQuery(value)
} catch (error) { }
}
async _handleKeyDown(e) {
if (e.key === 'Enter') {
try {
const value = this.shadowRoot.getElementById('linkInput').value
await this.getQuery(value)
} catch (error) { }
}
}
getApiKey() {
const apiNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
return apiNode.apiKey
}
isEmptyArray(arr) {
if (!arr) { return true }
return arr.length === 0
}
stateChanged(state) {
this.menuList = state.app.registeredUrls
this.addressInfo = state.app.accountInfo.addressInfo
}
}
window.customElements.define('nav-bar', NavBar)
class AppAvatar extends connect(store)(LitElement) {
static get properties() {
return {
hasAvatar: { type: Boolean },
isImageLoaded: { type: Boolean },
appicon: { type: String },
appname: { type: String }
}
}
static get styles() {
return [appAvatarStyles]
}
constructor() {
super()
this.hasAvatar = false
this.isImageLoaded = false
this.imageFetches = 0
}
render() {
let appAvatarImg = ''
if (this.appname) {
const appAvatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const appAvatarNodeUrl = appAvatarNode.protocol + '://' + appAvatarNode.domain + ':' + appAvatarNode.port
const appAvatarUrl = `${appAvatarNodeUrl}/arbitrary/THUMBNAIL/${this.appname}/qortal_avatar?async=true`
appAvatarImg = this.createImage(appAvatarUrl)
}
return html`
${this.isImageLoaded ?
html`
${appAvatarImg}
` : html`
`
}
`
}
firstUpdated() {
// ...
}
createImage(imageUrl) {
const imageHTMLRes = new Image()
imageHTMLRes.src = imageUrl
imageHTMLRes.style = "border-radius:10px; font-size:14px; object-fit: fill;height:60px;width:60px;"
imageHTMLRes.onload = () => {
this.isImageLoaded = true
}
imageHTMLRes.onerror = () => {
if (this.imageFetches < 1) {
setTimeout(() => {
this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl
}, 5000)
} else {
this.isImageLoaded = false
}
}
return imageHTMLRes
}
}
window.customElements.define('app-avatar', AppAvatar)
class TabAvatar extends connect(store)(LitElement) {
static get properties() {
return {
hasAvatar: { type: Boolean },
isImageLoaded: { type: Boolean },
appicon: { type: String },
appname: { type: String }
}
}
constructor() {
super()
this.hasAvatar = false
this.isImageLoaded = false
this.imageFetches = 0
}
render() {
let tabAvatarImg = ''
if (this.appname) {
const tabAvatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
const tabAvatarNodeUrl = tabAvatarNode.protocol + '://' + tabAvatarNode.domain + ':' + tabAvatarNode.port
const tabAvatarUrl = `${tabAvatarNodeUrl}/arbitrary/THUMBNAIL/${this.appname}/qortal_avatar?async=true`
tabAvatarImg = this.createImage(tabAvatarUrl)
}
return html`
${this.isImageLoaded ?
html`
${tabAvatarImg}
` : html`
${this.appicon}
`
}
`
}
firstUpdated() {
// ...
}
createImage(imageUrl) {
const imageHTMLRes = new Image()
imageHTMLRes.src = imageUrl
imageHTMLRes.style = "border-radius:4px; font-size:14px; object-fit: fill;height:24px;width:24px;"
imageHTMLRes.onload = () => {
this.isImageLoaded = true
}
imageHTMLRes.onerror = () => {
if (this.imageFetches < 1) {
setTimeout(() => {
this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl
}, 5000)
} else {
this.isImageLoaded = false
}
}
return imageHTMLRes
}
}
window.customElements.define('tab-avatar', TabAvatar)