mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-02-11 17:55:51 +00:00
Changed chat menu
This commit is contained in:
parent
47b490a943
commit
e22ff8cba0
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,9 +4,8 @@ yarn.lock
|
||||
# Derived js files
|
||||
qortal-ui-plugins/plugins/core/**/*.js
|
||||
!*.src.js
|
||||
qortal-ui-plugins/plugins/core/components/*.js
|
||||
!*.js
|
||||
qortal-ui-core/src/redux/app/version.js
|
||||
!qortal-ui-plugins/plugins/core/components/*.js
|
||||
|
||||
# Node modules
|
||||
node_modules/
|
||||
|
407
qortal-ui-plugins/plugins/core/components/ChatModals.js
Normal file
407
qortal-ui-plugins/plugins/core/components/ChatModals.js
Normal file
@ -0,0 +1,407 @@
|
||||
import { LitElement, html, css} from 'lit-element';
|
||||
import { get, translate } from 'lit-translate';
|
||||
import { Epml } from '../../../epml';
|
||||
import snackbar from './snackbar.js'
|
||||
import '@material/mwc-button';
|
||||
import '@material/mwc-dialog';
|
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||
|
||||
class ChatModals extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
openDialogPrivateMessage: {type: Boolean},
|
||||
openDialogBlockUser: {type: Boolean},
|
||||
isLoading: { type: Boolean },
|
||||
nametodialog: { type: String, attribute: true },
|
||||
hidePrivateMessageModal: {type: Function},
|
||||
hideBlockUserModal: {type: Function},
|
||||
toblockaddress: { type: String, attribute: true },
|
||||
chatBlockedAdresses: { type: Array },
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.isLoading = false;
|
||||
this.hidePrivateMessageModal = () => {};
|
||||
this.hideBlockUserModal = () => {};
|
||||
this.chatBlockedAdresses = []
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.input {
|
||||
width: 90%;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
resize: none;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
width: 90%;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
height: 120px;
|
||||
resize: none;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
display:block;
|
||||
--mdc-theme-primary: red;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
|
||||
const stopKeyEventPropagation = (e) => {
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation);
|
||||
this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation);
|
||||
|
||||
parentEpml.ready().then(() => {
|
||||
parentEpml.subscribe('selected_address', async selectedAddress => {
|
||||
this.selectedAddress = {}
|
||||
selectedAddress = JSON.parse(selectedAddress)
|
||||
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
|
||||
this.selectedAddress = selectedAddress
|
||||
})
|
||||
parentEpml.request('apiCall', {
|
||||
url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}`
|
||||
}).then(res => {
|
||||
this.balance = res
|
||||
})
|
||||
})
|
||||
parentEpml.imReady()
|
||||
|
||||
}
|
||||
|
||||
// Send Private Message
|
||||
|
||||
_sendMessage() {
|
||||
this.isLoading = true
|
||||
|
||||
const recipient = this.shadowRoot.getElementById('sendTo').value
|
||||
const messageBox = this.shadowRoot.getElementById('messageBox')
|
||||
const messageText = messageBox.value
|
||||
|
||||
if (recipient.length === 0) {
|
||||
this.isLoading = false
|
||||
} else if (messageText.length === 0) {
|
||||
this.isLoading = false
|
||||
} else {
|
||||
this.sendMessage()
|
||||
}
|
||||
}
|
||||
|
||||
async sendMessage() {
|
||||
this.isLoading = true
|
||||
|
||||
const _recipient = this.shadowRoot.getElementById('sendTo').value
|
||||
const messageBox = this.shadowRoot.getElementById('messageBox')
|
||||
const messageText = messageBox.value
|
||||
let recipient
|
||||
|
||||
const validateName = async (receiverName) => {
|
||||
let myRes
|
||||
let myNameRes = await parentEpml.request('apiCall', {
|
||||
type: 'api',
|
||||
url: `/names/${receiverName}`
|
||||
})
|
||||
|
||||
if (myNameRes.error === 401) {
|
||||
myRes = false
|
||||
} else {
|
||||
myRes = myNameRes
|
||||
}
|
||||
|
||||
return myRes
|
||||
}
|
||||
|
||||
const myNameRes = await validateName(_recipient)
|
||||
if (!myNameRes) {
|
||||
|
||||
recipient = _recipient
|
||||
} else {
|
||||
|
||||
recipient = myNameRes.owner
|
||||
}
|
||||
|
||||
let _reference = new Uint8Array(64);
|
||||
window.crypto.getRandomValues(_reference);
|
||||
|
||||
let sendTimestamp = Date.now()
|
||||
|
||||
let reference = window.parent.Base58.encode(_reference)
|
||||
|
||||
const getAddressPublicKey = async () => {
|
||||
let isEncrypted
|
||||
let _publicKey
|
||||
|
||||
let addressPublicKey = await parentEpml.request('apiCall', {
|
||||
type: 'api',
|
||||
url: `/addresses/publickey/${recipient}`
|
||||
})
|
||||
|
||||
|
||||
if (addressPublicKey.error === 102) {
|
||||
_publicKey = false
|
||||
// Do something here...
|
||||
let err1string = get('welcomepage.wcchange7')
|
||||
parentEpml.request('showSnackBar', `${err1string}`)
|
||||
this.isLoading = false
|
||||
} else if (addressPublicKey !== false) {
|
||||
isEncrypted = 1
|
||||
_publicKey = addressPublicKey
|
||||
sendMessageRequest(isEncrypted, _publicKey)
|
||||
} else {
|
||||
isEncrypted = 0
|
||||
_publicKey = this.selectedAddress.address
|
||||
sendMessageRequest(isEncrypted, _publicKey)
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessageRequest = async (isEncrypted, _publicKey) => {
|
||||
|
||||
let chatResponse = await parentEpml.request('chat', {
|
||||
type: 18,
|
||||
nonce: this.selectedAddress.nonce,
|
||||
params: {
|
||||
timestamp: sendTimestamp,
|
||||
recipient: recipient,
|
||||
recipientPublicKey: _publicKey,
|
||||
message: messageText,
|
||||
lastReference: reference,
|
||||
proofOfWorkNonce: 0,
|
||||
isEncrypted: isEncrypted,
|
||||
isText: 1
|
||||
}
|
||||
})
|
||||
_computePow(chatResponse)
|
||||
}
|
||||
|
||||
const _computePow = async (chatBytes) => {
|
||||
|
||||
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
|
||||
const chatBytesArray = new Uint8Array(_chatBytesArray)
|
||||
const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result
|
||||
const hashPtr = window.parent.sbrk(32, window.parent.heap);
|
||||
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
|
||||
hashAry.set(chatBytesHash);
|
||||
|
||||
const difficulty = this.balance === 0 ? 12 : 8;
|
||||
|
||||
const workBufferLength = 8 * 1024 * 1024;
|
||||
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
|
||||
|
||||
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
|
||||
|
||||
let _response = await parentEpml.request('sign_chat', {
|
||||
nonce: this.selectedAddress.nonce,
|
||||
chatBytesArray: chatBytesArray,
|
||||
chatNonce: nonce
|
||||
})
|
||||
getSendChatResponse(_response)
|
||||
}
|
||||
|
||||
const getSendChatResponse = (response) => {
|
||||
|
||||
if (response === true) {
|
||||
messageBox.value = ''
|
||||
let err2string = get('welcomepage.wcchange8')
|
||||
parentEpml.request('showSnackBar', `${err2string}`)
|
||||
this.isLoading = false
|
||||
this.shadowRoot.querySelector('#startPmDialog').close()
|
||||
} else if (response.error) {
|
||||
parentEpml.request('showSnackBar', response.message)
|
||||
this.isLoading = false
|
||||
this.shadowRoot.querySelector('#startPmDialog').close()
|
||||
} else {
|
||||
let err3string = get('welcomepage.wcchange9')
|
||||
parentEpml.request('showSnackBar', `${err3string}`)
|
||||
this.isLoading = false
|
||||
this.shadowRoot.querySelector('#startPmDialog').close()
|
||||
}
|
||||
|
||||
}
|
||||
getAddressPublicKey()
|
||||
}
|
||||
|
||||
_textArea(e) {
|
||||
if (e.keyCode === 13 && !e.shiftKey) this._sendMessage()
|
||||
}
|
||||
|
||||
getApiKey() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
|
||||
let apiKey = myNode.apiKey;
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
getChatBlockedList() {
|
||||
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 blockedAddressesUrl = `${nodeUrl}/lists/blockedAddresses?apiKey=${this.getApiKey()}`
|
||||
const err3string = 'No regitered name'
|
||||
|
||||
localStorage.removeItem("ChatBlockedAddresses")
|
||||
|
||||
var obj = [];
|
||||
|
||||
fetch(blockedAddressesUrl).then(response => {
|
||||
return response.json()
|
||||
}).then(data => {
|
||||
return data.map(item => {
|
||||
const noName = {
|
||||
name: err3string,
|
||||
owner: item
|
||||
}
|
||||
fetch(`${nodeUrl}/names/address/${item}?limit=0&reverse=true`).then(res => {
|
||||
return res.json()
|
||||
}).then(jsonRes => {
|
||||
if(jsonRes.length) {
|
||||
jsonRes.map (item => {
|
||||
obj.push(item)
|
||||
})
|
||||
} else {
|
||||
obj.push(noName)
|
||||
}
|
||||
localStorage.setItem("ChatBlockedAddresses", JSON.stringify(obj))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
relMessages() {
|
||||
setTimeout(() => {
|
||||
window.location.href = window.location.href.split( '#' )[0]
|
||||
}, 500)
|
||||
}
|
||||
|
||||
async getChatBlockedAdresses() {
|
||||
const chatBlockedAdresses = await parentEpml.request('apiCall', {
|
||||
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`
|
||||
})
|
||||
this.chatBlockedAdresses = chatBlockedAdresses
|
||||
}
|
||||
|
||||
|
||||
// Chat Block Address
|
||||
|
||||
async chatBlockAddress() {
|
||||
let address = this.toblockaddress
|
||||
|
||||
let items = [
|
||||
address
|
||||
]
|
||||
|
||||
let addressJsonString = JSON.stringify({ "items": items })
|
||||
|
||||
let ret = await parentEpml.request('apiCall', {
|
||||
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: `${addressJsonString}`
|
||||
})
|
||||
|
||||
if (ret === true) {
|
||||
this.chatBlockedAdresses = this.chatBlockedAdresses.filter(item => item != address)
|
||||
this.chatBlockedAdresses.push(address)
|
||||
this.getChatBlockedList()
|
||||
this.hideBlockUserModal()
|
||||
let err1string = get("blockpage.bcchange2")
|
||||
snackbar.add({
|
||||
labelText: `${err1string}`,
|
||||
dismiss: true
|
||||
})
|
||||
this.relMessages()
|
||||
} else {
|
||||
this.hideBlockUserModal()
|
||||
let err2string = get("blockpage.bcchange2")
|
||||
snackbar.add({
|
||||
labelText: `${err2string}`,
|
||||
dismiss: true
|
||||
})
|
||||
}
|
||||
console.log({ret})
|
||||
return ret
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<mwc-dialog
|
||||
id='sendPMDialog'
|
||||
tabindex='0'
|
||||
?open=${this.openDialogPrivateMessage}
|
||||
scrimClickAction='${this.isLoading ? '' : 'close'}'
|
||||
escapeKeyAction='close'
|
||||
defaultAction='close'
|
||||
@blur=${() => this.hidePrivateMessageModal()}
|
||||
>
|
||||
<div style='text-align:center'>
|
||||
<h1>${translate('welcomepage.wcchange2')}</h1>
|
||||
<hr>
|
||||
</div>
|
||||
<p>${translate('welcomepage.wcchange3')}</p>
|
||||
<textarea class='input' ?disabled=${this.isLoading} id='sendTo' rows='1'>${this.nametodialog}</textarea>
|
||||
<p style='margin-bottom:0;'>
|
||||
<textarea class='textarea' @keydown=${(e) => this._textArea(e)} ?disabled=${this.isLoading} id='messageBox' placeholder='${translate('welcomepage.wcchange5')}' rows='1'></textarea>
|
||||
</p>
|
||||
<mwc-button ?disabled='${this.isLoading}' slot='primaryAction' @click=${this._sendMessage}>${translate('welcomepage.wcchange6')}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
?disabled='${this.isLoading}'
|
||||
slot='secondaryAction'
|
||||
@click='${() => this.hidePrivateMessageModal()}'
|
||||
class='close-button'
|
||||
>
|
||||
${translate('general.close')}
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
<mwc-dialog
|
||||
id='blockNameDialog'
|
||||
tabindex='0'
|
||||
?open=${this.openDialogBlockUser}
|
||||
escapeKeyAction='close'
|
||||
defaultAction='close'
|
||||
@blur=${() => this.hideBlockUserModal()}
|
||||
>
|
||||
<div style='text-align:center'>
|
||||
<h1>${translate('blockpage.bcchange5')}</h1>
|
||||
<hr>
|
||||
<h2>${translate('blockpage.bcchange6')}</h2><br>
|
||||
<h2>${this.nametodialog}</h2>
|
||||
</div>
|
||||
<mwc-button
|
||||
slot='secondaryAction'
|
||||
@click='${() => this.chatBlockAddress()}'
|
||||
class='block'
|
||||
>
|
||||
${translate('general.yes')}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
slot='primaryAction'
|
||||
@click='${() => this.hideBlockUserModal()}'
|
||||
class='close-button'
|
||||
>
|
||||
${translate('general.no')}
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('chat-modals', ChatModals);
|
@ -4,7 +4,7 @@ import { Epml } from '../../../epml.js'
|
||||
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||
|
||||
registerTranslateConfig({
|
||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||
})
|
||||
|
||||
import { escape, unescape } from 'html-escaper';
|
||||
@ -44,7 +44,8 @@ class ChatPage extends LitElement {
|
||||
isPasteMenuOpen: { type: Boolean },
|
||||
showNewMesssageBar: { attribute: false },
|
||||
hideNewMesssageBar: { attribute: false },
|
||||
chatEditorPlaceholder: { type: String }
|
||||
chatEditorPlaceholder: { type: String },
|
||||
messagesRendered: { type: Array },
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +134,7 @@ class ChatPage extends LitElement {
|
||||
this.isUserDown = false
|
||||
this.isPasteMenuOpen = false
|
||||
this.chatEditorPlaceholder = this.renderPlaceholder()
|
||||
this.messagesRendered = []
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -153,7 +155,7 @@ class ChatPage extends LitElement {
|
||||
firstUpdated() {
|
||||
// TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...)
|
||||
|
||||
this.changeLanguage();
|
||||
// this.changeLanguage();
|
||||
this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button');
|
||||
this.mirrorChatInput = this.shadowRoot.getElementById('messageBox');
|
||||
this.chatMessageInput = this.shadowRoot.getElementById('_chatEditorDOM');
|
||||
@ -169,7 +171,7 @@ class ChatPage extends LitElement {
|
||||
} else {
|
||||
return this.chatEditor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Init EmojiPicker
|
||||
@ -279,19 +281,32 @@ class ChatPage extends LitElement {
|
||||
}
|
||||
|
||||
renderChatScroller(initialMessages) {
|
||||
return html`<chat-scroller .initialMessages=${initialMessages} .emojiPicker=${this.emojiPicker} .escapeHTML=${escape} .getOldMessage=${this.getOldMessage} > </chat-scroller>`
|
||||
return html`<chat-scroller .initialMessages=${initialMessages} .messages=${this.messagesRendered} .emojiPicker=${this.emojiPicker} .escapeHTML=${escape} .getOldMessage=${this.getOldMessage} > </chat-scroller>`
|
||||
}
|
||||
|
||||
getOldMessage(scrollElement) {
|
||||
async getUpdateComplete() {
|
||||
await super.getUpdateComplete();
|
||||
const marginElements = Array.from(this.shadowRoot.querySelectorAll('chat-scroller'));
|
||||
await Promise.all(marginElements.map(el => el.updateComplete));
|
||||
return true;
|
||||
}
|
||||
|
||||
async getOldMessage(scrollElement) {
|
||||
|
||||
if (this._messages.length <= 15 && this._messages.length >= 1) { // 15 is the default number of messages...
|
||||
|
||||
let __msg = [...this._messages]
|
||||
this._messages = []
|
||||
this.messagesRendered = [...__msg, ...this.messagesRendered]
|
||||
await this.getUpdateComplete();
|
||||
|
||||
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||
return { oldMessages: __msg, scrollElement: scrollElement }
|
||||
} else if (this._messages.length > 15) {
|
||||
this.messagesRendered = [...this._messages.splice(this._messages.length - 15), ...this.messagesRendered]
|
||||
await this.getUpdateComplete();
|
||||
|
||||
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||
return { oldMessages: this._messages.splice(this._messages.length - 15), scrollElement: scrollElement }
|
||||
} else {
|
||||
|
||||
@ -299,8 +314,8 @@ class ChatPage extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
processMessages(messages, isInitial) {
|
||||
|
||||
async processMessages(messages, isInitial) {
|
||||
console.log({ messages })
|
||||
if (isInitial) {
|
||||
|
||||
this.messages = messages.map((eachMessage) => {
|
||||
@ -328,6 +343,18 @@ class ChatPage extends LitElement {
|
||||
// TODO: Determine number of initial messages by screen height...
|
||||
this._messages.length <= 15 ? adjustMessages() : this._initialMessages = this._messages.splice(this._messages.length - 15);
|
||||
|
||||
|
||||
this.messagesRendered = this._initialMessages
|
||||
|
||||
// try {
|
||||
// const viewElement = this.shadowRoot.querySelector('chat-scroller')
|
||||
// console.log({viewElement})
|
||||
// // viewElement.scrollTop = this.viewElement.scrollHeight + 50
|
||||
// } catch (error) {
|
||||
// console.error(error)
|
||||
// }
|
||||
|
||||
|
||||
this.isLoadingMessages = false
|
||||
setTimeout(() => this.downElementObserver(), 500)
|
||||
} else {
|
||||
@ -355,6 +382,7 @@ class ChatPage extends LitElement {
|
||||
|
||||
this.newMessages = this.newMessages.concat(_newMessages)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +415,7 @@ class ChatPage extends LitElement {
|
||||
nameMenu = `<name-menu toblockaddress="${messageObj.sender}" nametodialog="${messageObj.senderName ? messageObj.senderName : messageObj.sender}"></name-menu>`
|
||||
}
|
||||
|
||||
if ( hideit === true ) {
|
||||
if (hideit === true) {
|
||||
return `
|
||||
<li class="clearfix"></li>
|
||||
`
|
||||
@ -406,7 +434,7 @@ class ChatPage extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
renderNewMessage(newMessage) {
|
||||
async renderNewMessage(newMessage) {
|
||||
|
||||
const viewElement = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement');
|
||||
const downObserver = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('downObserver');
|
||||
@ -416,16 +444,22 @@ class ChatPage extends LitElement {
|
||||
|
||||
if (newMessage.sender === this.selectedAddress.address) {
|
||||
|
||||
viewElement.insertBefore(li, downObserver);
|
||||
this.messagesRendered = [...this.messagesRendered, newMessage]
|
||||
await this.getUpdateComplete();
|
||||
|
||||
viewElement.scrollTop = viewElement.scrollHeight;
|
||||
} else if (this.isUserDown) {
|
||||
|
||||
// Append the message and scroll to the bottom if user is down the page
|
||||
viewElement.insertBefore(li, downObserver);
|
||||
this.messagesRendered = [...this.messagesRendered, newMessage]
|
||||
await this.getUpdateComplete();
|
||||
|
||||
viewElement.scrollTop = viewElement.scrollHeight;
|
||||
} else {
|
||||
|
||||
viewElement.insertBefore(li, downObserver);
|
||||
this.messagesRendered = [...this.messagesRendered, newMessage]
|
||||
await this.getUpdateComplete();
|
||||
|
||||
this.showNewMesssageBar();
|
||||
}
|
||||
}
|
||||
@ -843,7 +877,7 @@ class ChatPage extends LitElement {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
`;
|
||||
editor.content.head.appendChild(editor.styles);
|
||||
editor.content.head.appendChild(editor.styles);
|
||||
};
|
||||
|
||||
ChatEditor.prototype.enable = function () {
|
||||
@ -1030,7 +1064,7 @@ class ChatPage extends LitElement {
|
||||
|
||||
function doInit() {
|
||||
return new ChatEditor();
|
||||
};
|
||||
}
|
||||
return doInit();
|
||||
};
|
||||
|
||||
|
@ -1,16 +1,18 @@
|
||||
import { LitElement, html, css } from 'lit'
|
||||
import { render } from 'lit/html.js'
|
||||
import { Epml } from '../../../epml.js'
|
||||
|
||||
import './LevelFounder.js'
|
||||
import './NameMenu.js'
|
||||
|
||||
import '@material/mwc-button'
|
||||
import '@material/mwc-dialog'
|
||||
import '@material/mwc-icon'
|
||||
import { LitElement, html, css } from 'lit';
|
||||
import { render } from 'lit/html.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
import { translate, get } from 'lit-translate';
|
||||
import { Epml } from "../../../epml";
|
||||
import './LevelFounder.js';
|
||||
import './NameMenu.js';
|
||||
import './ChatModals.js';
|
||||
import '@vaadin/icons';
|
||||
import '@vaadin/icon';
|
||||
import '@material/mwc-button';
|
||||
import '@material/mwc-dialog';
|
||||
import '@material/mwc-icon';
|
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||
|
||||
class ChatScroller extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@ -63,8 +65,29 @@ class ChatScroller extends LitElement {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.last-message-ref {
|
||||
position: fixed;
|
||||
font-size: 20px;
|
||||
right: 40px;
|
||||
bottom: 100px;
|
||||
width: 50;
|
||||
height: 50;
|
||||
z-index: 5;
|
||||
opacity: 0;
|
||||
color: black;
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.last-message-ref:hover {
|
||||
cursor: pointer;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 92vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@ -77,7 +100,6 @@ class ChatScroller extends LitElement {
|
||||
|
||||
.message-data-name {
|
||||
color: var(--black);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.message-data-time {
|
||||
@ -190,7 +212,7 @@ class ChatScroller extends LitElement {
|
||||
super()
|
||||
this.messages = []
|
||||
this._upObserverhandler = this._upObserverhandler.bind(this)
|
||||
this.isLoading = false
|
||||
this._downObserverHandler = this._downObserverHandler.bind(this)
|
||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
|
||||
}
|
||||
@ -200,103 +222,61 @@ class ChatScroller extends LitElement {
|
||||
return html`
|
||||
<ul id="viewElement" class="chat-list clearfix">
|
||||
<div id="upObserver"></div>
|
||||
<div id="downObserver"></div>
|
||||
|
||||
${repeat(
|
||||
this.messages,
|
||||
(message) => message.reference,
|
||||
(message) => html`<message-template .emojiPicker=${this.emojiPicker} .escapeHTML=${this.escapeHTML} .messageObj=${message} .hideMessages=${this.hideMessages}></message-template>`
|
||||
)}
|
||||
<div id='downObserver'></div>
|
||||
<div class='last-message-ref'>
|
||||
<vaadin-icon icon='vaadin:arrow-circle-down' slot='icon' @click=${() => {
|
||||
console.log("yo500")
|
||||
this.shadowRoot.getElementById('downObserver').scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}}></vaadin-icon>
|
||||
</div>
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
async firstUpdated() {
|
||||
this.viewElement = this.shadowRoot.getElementById('viewElement')
|
||||
this.upObserverElement = this.shadowRoot.getElementById('upObserver')
|
||||
this.downObserverElement = this.shadowRoot.getElementById('downObserver')
|
||||
this.renderChatMessages(this.initialMessages)
|
||||
|
||||
|
||||
// Intialize Observers
|
||||
this.upElementObserver()
|
||||
|
||||
this.downElementObserver()
|
||||
await this.updateComplete
|
||||
this.viewElement.scrollTop = this.viewElement.scrollHeight + 50
|
||||
}
|
||||
|
||||
chatMessageTemplate(messageObj) {
|
||||
const hidemsg = this.hideMessages
|
||||
|
||||
let avatarImg = ''
|
||||
let nameMenu = ''
|
||||
let levelFounder = ''
|
||||
let hideit = hidemsg.includes(messageObj.sender)
|
||||
|
||||
levelFounder = `<level-founder checkleveladdress="${messageObj.sender}"></level-founder>`
|
||||
|
||||
if (messageObj.senderName) {
|
||||
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 avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${messageObj.senderName}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`
|
||||
avatarImg = `<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`
|
||||
}
|
||||
|
||||
if (messageObj.sender === this.myAddress) {
|
||||
nameMenu = `<span style="color: #03a9f4;">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span>`
|
||||
} else {
|
||||
nameMenu = `<name-menu toblockaddress="${messageObj.sender}" nametodialog="${messageObj.senderName ? messageObj.senderName : messageObj.sender}"></name-menu>`
|
||||
}
|
||||
|
||||
if ( hideit === true ) {
|
||||
return `
|
||||
<li class="clearfix"></li>
|
||||
`
|
||||
} else {
|
||||
return `
|
||||
<li class="clearfix">
|
||||
<div class="message-data ${messageObj.sender === this.myAddress ? "" : ""}">
|
||||
<span class="message-data-name">${nameMenu}</span>
|
||||
<span class="message-data-level">${levelFounder}</span>
|
||||
<span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span>
|
||||
</div>
|
||||
<div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.myAddress ? "float:left;" : "float:left;"} margin:3px;">${avatarImg}</div>
|
||||
<div id="messageContent" class="message ${messageObj.sender === this.myAddress ? "my-message float-left" : "other-message float-left"}">${this.emojiPicker.parse(this.escapeHTML(messageObj.decodedMessage))}</div>
|
||||
</li>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
renderChatMessages(messages) {
|
||||
messages.forEach(message => {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = this.chatMessageTemplate(message);
|
||||
li.id = message.signature;
|
||||
this.downObserverElement.before(li);
|
||||
});
|
||||
}
|
||||
|
||||
renderOldMessages(listOfOldMessages) {
|
||||
let { oldMessages, scrollElement } = listOfOldMessages;
|
||||
|
||||
let _oldMessages = oldMessages.reverse();
|
||||
_oldMessages.forEach(oldMessage => {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = this.chatMessageTemplate(oldMessage);
|
||||
li.id = oldMessage.signature;
|
||||
this.upObserverElement.after(li);
|
||||
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||
});
|
||||
}
|
||||
|
||||
_getOldMessage(_scrollElement) {
|
||||
let listOfOldMessages = this.getOldMessage(_scrollElement)
|
||||
this.getOldMessage(_scrollElement)
|
||||
|
||||
|
||||
if (listOfOldMessages) {
|
||||
this.renderOldMessages(listOfOldMessages)
|
||||
}
|
||||
}
|
||||
|
||||
_upObserverhandler(entries) {
|
||||
if (entries[0].isIntersecting) {
|
||||
let _scrollElement = entries[0].target.nextElementSibling
|
||||
|
||||
console.log({ _scrollElement })
|
||||
this._getOldMessage(_scrollElement)
|
||||
}
|
||||
}
|
||||
|
||||
_downObserverHandler(entries) {
|
||||
|
||||
if (!entries[0].isIntersecting) {
|
||||
this.shadowRoot.querySelector(".last-message-ref").style.opacity = '1'
|
||||
} else {
|
||||
this.shadowRoot.querySelector(".last-message-ref").style.opacity = '0'
|
||||
}
|
||||
}
|
||||
|
||||
upElementObserver() {
|
||||
const options = {
|
||||
root: this.viewElement,
|
||||
@ -307,6 +287,475 @@ class ChatScroller extends LitElement {
|
||||
const observer = new IntersectionObserver(this._upObserverhandler, options)
|
||||
observer.observe(this.upObserverElement)
|
||||
}
|
||||
|
||||
downElementObserver() {
|
||||
const options = {
|
||||
root: this.viewElement,
|
||||
rootMargin: '0px',
|
||||
threshold: 1
|
||||
};
|
||||
// identify an element to observe
|
||||
const elementToObserve = this.downObserverElement;
|
||||
|
||||
// passing it a callback function
|
||||
const observer = new IntersectionObserver(this._downObserverHandler, options);
|
||||
|
||||
// call `observe()` on that MutationObserver instance,
|
||||
// passing it the element to observe, and the options object
|
||||
observer.observe(elementToObserve);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.customElements.define('chat-scroller', ChatScroller)
|
||||
|
||||
|
||||
class MessageTemplate extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
messageObj: { type: Object },
|
||||
hideMessages: { type: Array },
|
||||
openDialogPrivateMessage: {type: Boolean},
|
||||
openDialogBlockUser: {type: Boolean},
|
||||
showBlockAddressIcon: { type: Boolean },
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.messageObj = {}
|
||||
this.openDialogPrivateMessage = false
|
||||
this.openDialogBlockUser = false
|
||||
this.showBlockAddressIcon = false
|
||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
html {
|
||||
--scrollbarBG: #a1a1a1;
|
||||
--thumbBG: #6a6c75;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 11px;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
|
||||
--mdc-theme-primary: rgb(3, 169, 244);
|
||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: var(--scrollbarBG);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: var(--thumbBG);
|
||||
border-radius: 6px;
|
||||
border: 3px solid var(--scrollbarBG);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--black);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 92vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.message-data {
|
||||
width: 92%;
|
||||
margin-bottom: 15px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.message-data-name {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.message-data-time {
|
||||
color: #a8aab1;
|
||||
font-size: 13px;
|
||||
padding-left: 6px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.message-data-level {
|
||||
color: #03a9f4;
|
||||
font-size: 13px;
|
||||
padding-left: 8px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: black;
|
||||
padding: 12px 10px;
|
||||
line-height: 19px;
|
||||
white-space: pre-line;
|
||||
word-wrap: break-word;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
font-size: 16px;
|
||||
border-radius: 7px;
|
||||
margin-bottom: 20px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message:after {
|
||||
bottom: 100%;
|
||||
left: 93%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
white-space: pre-line;
|
||||
word-wrap: break-word;
|
||||
pointer-events: none;
|
||||
border-bottom-color: #ddd;
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.message-parent:hover .chat-hover {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.message-parent:hover .message{
|
||||
filter:brightness(0.90);
|
||||
}
|
||||
|
||||
.chat-hover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -32px;
|
||||
left: 86%;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
width: 1.7em;
|
||||
height: 1.5em;
|
||||
margin-bottom: -2px;
|
||||
vertical-align: bottom;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.my-message {
|
||||
background: #d1d1d1;
|
||||
border: 2px solid #eeeeee;
|
||||
}
|
||||
|
||||
.my-message:after {
|
||||
border-bottom-color: #d1d1d1;
|
||||
left: 7%;
|
||||
}
|
||||
|
||||
.other-message {
|
||||
background: #f1f1f1;
|
||||
border: 2px solid #dedede;
|
||||
}
|
||||
|
||||
.other-message:after {
|
||||
border-bottom-color: #f1f1f1;
|
||||
left: 7%;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 25%;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
// Open & Close Private Message Chat Modal
|
||||
|
||||
showPrivateMessageModal() {
|
||||
this.openDialogPrivateMessage = true
|
||||
}
|
||||
|
||||
hidePrivateMessageModal() {
|
||||
this.openDialogPrivateMessage = false
|
||||
}
|
||||
|
||||
// Open & Close Block User Chat Modal
|
||||
|
||||
showBlockUserModal() {
|
||||
this.openDialogBlockUser = true
|
||||
}
|
||||
|
||||
hideBlockUserModal() {
|
||||
this.openDialogBlockUser = false
|
||||
}
|
||||
|
||||
showBlockIconFunc(bool) {
|
||||
this.shadowRoot.querySelector(".chat-hover").focus({ preventScroll: true })
|
||||
if(bool) {
|
||||
this.showBlockAddressIcon = true;
|
||||
} else {
|
||||
this.showBlockAddressIcon = false;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log(this.showBlockAddressIcon)
|
||||
const hidemsg = this.hideMessages
|
||||
|
||||
let avatarImg = ''
|
||||
let nameMenu = ''
|
||||
let levelFounder = ''
|
||||
let hideit = hidemsg.includes(this.messageObj.sender)
|
||||
|
||||
levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>`
|
||||
|
||||
if (this.messageObj.senderName) {
|
||||
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 avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.messageObj.senderName}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`
|
||||
avatarImg = html`<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`
|
||||
}
|
||||
|
||||
if (this.messageObj.sender === this.myAddress) {
|
||||
nameMenu = html`<span style="color: #03a9f4;">${this.messageObj.senderName ? this.messageObj.senderName : this.messageObj.sender}</span>`
|
||||
} else {
|
||||
nameMenu = html`<span>${this.messageObj.senderName ? this.messageObj.senderName : this.messageObj.sender}</span>`
|
||||
}
|
||||
|
||||
return hideit ? html`<li class="clearfix"></li>` : html`
|
||||
<li class="clearfix message-parent">
|
||||
<div class="message-data ${this.messageObj.sender === this.myAddress ? "" : ""}">
|
||||
<span class="message-data-name">${nameMenu}</span>
|
||||
<span class="message-data-level">${levelFounder}</span>
|
||||
<span class="message-data-time"><message-time timestamp=${this.messageObj.timestamp}></message-time></span>
|
||||
</div>
|
||||
<div class="message-data-avatar" style="width:42px; height:42px; ${this.messageObj.sender === this.myAddress ? "float:left;" : "float:left;"} margin:3px;">${avatarImg}</div>
|
||||
<div class="message-container">
|
||||
<div id="messageContent" class="message ${this.messageObj.sender === this.myAddress ? "my-message float-left" : "other-message float-left"}">${this.emojiPicker.parse(this.escapeHTML(this.messageObj.decodedMessage))}</div>
|
||||
<chat-menu
|
||||
tabindex="0"
|
||||
class="chat-hover"
|
||||
style=${this.showBlockAddressIcon && "display: block"}
|
||||
toblockaddress="${this.messageObj.sender}"
|
||||
.showPrivateMessageModal=${() => this.showPrivateMessageModal()}
|
||||
.showBlockUserModal=${() => this.showBlockUserModal()}
|
||||
.showBlockIconFunc=${(props) => this.showBlockIconFunc(props)}
|
||||
.showBlockAddressIcon=${this.showBlockAddressIcon}
|
||||
@blur=${() => this.showBlockIconFunc(false)}
|
||||
>
|
||||
</chat-menu>
|
||||
</div>
|
||||
</li>
|
||||
<chat-modals
|
||||
.openDialogPrivateMessage=${this.openDialogPrivateMessage}
|
||||
.openDialogBlockUser=${this.openDialogBlockUser}
|
||||
nametodialog="${this.messageObj.senderName ? this.messageObj.senderName : this.messageObj.sender}"
|
||||
.hidePrivateMessageModal=${() => this.hidePrivateMessageModal()}
|
||||
.hideBlockUserModal=${() => this.hideBlockUserModal()}
|
||||
toblockaddress=${this.messageObj.sender}
|
||||
>
|
||||
</chat-modals>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('message-template', MessageTemplate);
|
||||
|
||||
class ChatMenu extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
menuItems: { type: Array },
|
||||
selectedAddress: { type: Object },
|
||||
showPrivateMessageModal: {type: Function},
|
||||
showBlockUserModal: {type: Function},
|
||||
toblockaddress: { type: String, attribute: true },
|
||||
showBlockIconFunc: {type: Function},
|
||||
showBlockAddressIcon: {type: Boolean}
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.selectedAddress = window.parent.reduxStore.getState().app.selectedAddress.address;
|
||||
this.showPrivateMessageModal = () => {};
|
||||
this.showBlockUserModal = () => {};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
background-color: white;
|
||||
border: 1px solid #dad9d9;
|
||||
border-radius: 5px;
|
||||
height:100%;
|
||||
width: 100px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.menu-icon:hover {
|
||||
background-color: #dad9d9;
|
||||
transition: all 0.1s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip:before {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: -47px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 90px;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
background:#fff;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
|
||||
font-size: 12px;
|
||||
z-index: 5;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tooltip:hover:before {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tooltip:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
margin-top: -7px;
|
||||
top: -7px;
|
||||
border: 10px solid #fff;
|
||||
border-color: white transparent transparent transparent;
|
||||
z-index: 5;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tooltip:hover:before, .tooltip:hover:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.block-user-container {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
}
|
||||
|
||||
.block-user {
|
||||
justify-content: space-between;
|
||||
border: 1px solid rgb(218, 217, 217);
|
||||
border-radius: 5px;
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding: 3px 8px;
|
||||
box-shadow: rgba(77, 77, 82, 0.2) 0px 7px 29px 0px;
|
||||
}
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
// Copy address to clipboard
|
||||
|
||||
async copyToClipboard(text) {
|
||||
try {
|
||||
let copyString1 = get("walletpage.wchange4")
|
||||
await navigator.clipboard.writeText(text)
|
||||
parentEpml.request('showSnackBar', `${copyString1}`)
|
||||
} catch (err) {
|
||||
let copyString2 = get("walletpage.wchange39")
|
||||
parentEpml.request('showSnackBar', `${copyString2}`)
|
||||
console.error('Copy to clipboard error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return html`
|
||||
<div class="container" style=${this.showBlockAddressIcon && "width: 70px" }>
|
||||
<div class="menu-icon tooltip" data-text="Private Message"
|
||||
@click="${() => this.showPrivateMessageModal()}">
|
||||
<vaadin-icon icon="vaadin:paperplane" slot="icon"></vaadin-icon>
|
||||
</div>
|
||||
<div class="menu-icon tooltip" data-text="Copy Address" @click="${() => this.copyToClipboard(this.toblockaddress)}">
|
||||
<vaadin-icon icon="vaadin:copy" slot="icon"></vaadin-icon>
|
||||
</div>
|
||||
<div class="menu-icon tooltip" data-text="More" @click="${() => this.showBlockIconFunc(true)}">
|
||||
<vaadin-icon icon="vaadin:ellipsis-dots-h" slot="icon"></vaadin-icon>
|
||||
</div>
|
||||
${this.showBlockAddressIcon ? html`
|
||||
<div class="block-user-container">
|
||||
<div class="menu-icon block-user" @click="${() => this.showBlockUserModal()}">
|
||||
<p>${translate("blockpage.bcchange1")}</p>
|
||||
<vaadin-icon icon="vaadin:close-circle" slot="icon"></vaadin-icon>
|
||||
</div>
|
||||
</div>
|
||||
` : html`
|
||||
<div></div>
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('chat-menu', ChatMenu);
|
||||
|
||||
|
@ -245,9 +245,7 @@ class ChatWelcomePage extends LitElement {
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
|
||||
this.changeTheme()
|
||||
this.changeLanguage()
|
||||
|
||||
const stopKeyEventPropagation = (e) => {
|
||||
e.stopPropagation();
|
||||
|
@ -95,8 +95,6 @@ class LevelFounder extends LitElement {
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
|
||||
this.changeLanguage()
|
||||
this.checkAddressInfo()
|
||||
|
||||
window.addEventListener('storage', () => {
|
||||
|
@ -246,8 +246,6 @@ class NameMenu extends LitElement {
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
|
||||
this.changeLanguage()
|
||||
this.getChatBlockedAdresses()
|
||||
|
||||
setInterval(() => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user