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
|
# Derived js files
|
||||||
qortal-ui-plugins/plugins/core/**/*.js
|
qortal-ui-plugins/plugins/core/**/*.js
|
||||||
!*.src.js
|
!*.src.js
|
||||||
qortal-ui-plugins/plugins/core/components/*.js
|
|
||||||
!*.js
|
|
||||||
qortal-ui-core/src/redux/app/version.js
|
qortal-ui-core/src/redux/app/version.js
|
||||||
|
!qortal-ui-plugins/plugins/core/components/*.js
|
||||||
|
|
||||||
# Node modules
|
# Node modules
|
||||||
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'
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
registerTranslateConfig({
|
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';
|
import { escape, unescape } from 'html-escaper';
|
||||||
@ -44,7 +44,8 @@ class ChatPage extends LitElement {
|
|||||||
isPasteMenuOpen: { type: Boolean },
|
isPasteMenuOpen: { type: Boolean },
|
||||||
showNewMesssageBar: { attribute: false },
|
showNewMesssageBar: { attribute: false },
|
||||||
hideNewMesssageBar: { 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.isUserDown = false
|
||||||
this.isPasteMenuOpen = false
|
this.isPasteMenuOpen = false
|
||||||
this.chatEditorPlaceholder = this.renderPlaceholder()
|
this.chatEditorPlaceholder = this.renderPlaceholder()
|
||||||
|
this.messagesRendered = []
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -153,7 +155,7 @@ class ChatPage extends LitElement {
|
|||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
// TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...)
|
// TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...)
|
||||||
|
|
||||||
this.changeLanguage();
|
// this.changeLanguage();
|
||||||
this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button');
|
this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button');
|
||||||
this.mirrorChatInput = this.shadowRoot.getElementById('messageBox');
|
this.mirrorChatInput = this.shadowRoot.getElementById('messageBox');
|
||||||
this.chatMessageInput = this.shadowRoot.getElementById('_chatEditorDOM');
|
this.chatMessageInput = this.shadowRoot.getElementById('_chatEditorDOM');
|
||||||
@ -169,7 +171,7 @@ class ChatPage extends LitElement {
|
|||||||
} else {
|
} else {
|
||||||
return this.chatEditor.focus();
|
return this.chatEditor.focus();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Init EmojiPicker
|
// Init EmojiPicker
|
||||||
@ -279,19 +281,32 @@ class ChatPage extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderChatScroller(initialMessages) {
|
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...
|
if (this._messages.length <= 15 && this._messages.length >= 1) { // 15 is the default number of messages...
|
||||||
|
|
||||||
let __msg = [...this._messages]
|
let __msg = [...this._messages]
|
||||||
this._messages = []
|
this._messages = []
|
||||||
|
this.messagesRendered = [...__msg, ...this.messagesRendered]
|
||||||
|
await this.getUpdateComplete();
|
||||||
|
|
||||||
|
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||||
return { oldMessages: __msg, scrollElement: scrollElement }
|
return { oldMessages: __msg, scrollElement: scrollElement }
|
||||||
} else if (this._messages.length > 15) {
|
} 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 }
|
return { oldMessages: this._messages.splice(this._messages.length - 15), scrollElement: scrollElement }
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -299,8 +314,8 @@ class ChatPage extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processMessages(messages, isInitial) {
|
async processMessages(messages, isInitial) {
|
||||||
|
console.log({ messages })
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
|
|
||||||
this.messages = messages.map((eachMessage) => {
|
this.messages = messages.map((eachMessage) => {
|
||||||
@ -327,7 +342,19 @@ class ChatPage extends LitElement {
|
|||||||
|
|
||||||
// TODO: Determine number of initial messages by screen height...
|
// TODO: Determine number of initial messages by screen height...
|
||||||
this._messages.length <= 15 ? adjustMessages() : this._initialMessages = this._messages.splice(this._messages.length - 15);
|
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
|
this.isLoadingMessages = false
|
||||||
setTimeout(() => this.downElementObserver(), 500)
|
setTimeout(() => this.downElementObserver(), 500)
|
||||||
} else {
|
} else {
|
||||||
@ -354,6 +381,7 @@ class ChatPage extends LitElement {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.newMessages = this.newMessages.concat(_newMessages)
|
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>`
|
nameMenu = `<name-menu toblockaddress="${messageObj.sender}" nametodialog="${messageObj.senderName ? messageObj.senderName : messageObj.sender}"></name-menu>`
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hideit === true ) {
|
if (hideit === true) {
|
||||||
return `
|
return `
|
||||||
<li class="clearfix"></li>
|
<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 viewElement = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement');
|
||||||
const downObserver = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('downObserver');
|
const downObserver = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('downObserver');
|
||||||
@ -416,16 +444,22 @@ class ChatPage extends LitElement {
|
|||||||
|
|
||||||
if (newMessage.sender === this.selectedAddress.address) {
|
if (newMessage.sender === this.selectedAddress.address) {
|
||||||
|
|
||||||
viewElement.insertBefore(li, downObserver);
|
this.messagesRendered = [...this.messagesRendered, newMessage]
|
||||||
|
await this.getUpdateComplete();
|
||||||
|
|
||||||
viewElement.scrollTop = viewElement.scrollHeight;
|
viewElement.scrollTop = viewElement.scrollHeight;
|
||||||
} else if (this.isUserDown) {
|
} else if (this.isUserDown) {
|
||||||
|
|
||||||
// Append the message and scroll to the bottom if user is down the page
|
// 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;
|
viewElement.scrollTop = viewElement.scrollHeight;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
viewElement.insertBefore(li, downObserver);
|
this.messagesRendered = [...this.messagesRendered, newMessage]
|
||||||
|
await this.getUpdateComplete();
|
||||||
|
|
||||||
this.showNewMesssageBar();
|
this.showNewMesssageBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -843,7 +877,7 @@ class ChatPage extends LitElement {
|
|||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
editor.content.head.appendChild(editor.styles);
|
editor.content.head.appendChild(editor.styles);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChatEditor.prototype.enable = function () {
|
ChatEditor.prototype.enable = function () {
|
||||||
@ -1030,7 +1064,7 @@ class ChatPage extends LitElement {
|
|||||||
|
|
||||||
function doInit() {
|
function doInit() {
|
||||||
return new ChatEditor();
|
return new ChatEditor();
|
||||||
};
|
}
|
||||||
return doInit();
|
return doInit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
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 { repeat } from 'lit/directives/repeat.js';
|
||||||
|
import { translate, get } from 'lit-translate';
|
||||||
import './LevelFounder.js'
|
import { Epml } from "../../../epml";
|
||||||
import './NameMenu.js'
|
import './LevelFounder.js';
|
||||||
|
import './NameMenu.js';
|
||||||
import '@material/mwc-button'
|
import './ChatModals.js';
|
||||||
import '@material/mwc-dialog'
|
import '@vaadin/icons';
|
||||||
import '@material/mwc-icon'
|
import '@vaadin/icon';
|
||||||
|
import '@material/mwc-button';
|
||||||
|
import '@material/mwc-dialog';
|
||||||
|
import '@material/mwc-icon';
|
||||||
|
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
class ChatScroller extends LitElement {
|
class ChatScroller extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -63,8 +65,29 @@ class ChatScroller extends LitElement {
|
|||||||
padding: 20px;
|
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 {
|
.chat-list {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
height: 92vh;
|
height: 92vh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@ -77,7 +100,6 @@ class ChatScroller extends LitElement {
|
|||||||
|
|
||||||
.message-data-name {
|
.message-data-name {
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-data-time {
|
.message-data-time {
|
||||||
@ -190,7 +212,7 @@ class ChatScroller extends LitElement {
|
|||||||
super()
|
super()
|
||||||
this.messages = []
|
this.messages = []
|
||||||
this._upObserverhandler = this._upObserverhandler.bind(this)
|
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.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||||
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
|
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
|
||||||
}
|
}
|
||||||
@ -200,103 +222,61 @@ class ChatScroller extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ul id="viewElement" class="chat-list clearfix">
|
<ul id="viewElement" class="chat-list clearfix">
|
||||||
<div id="upObserver"></div>
|
<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>
|
</ul>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
async firstUpdated() {
|
||||||
this.viewElement = this.shadowRoot.getElementById('viewElement')
|
this.viewElement = this.shadowRoot.getElementById('viewElement')
|
||||||
this.upObserverElement = this.shadowRoot.getElementById('upObserver')
|
this.upObserverElement = this.shadowRoot.getElementById('upObserver')
|
||||||
this.downObserverElement = this.shadowRoot.getElementById('downObserver')
|
this.downObserverElement = this.shadowRoot.getElementById('downObserver')
|
||||||
this.renderChatMessages(this.initialMessages)
|
|
||||||
|
|
||||||
// Intialize Observers
|
// Intialize Observers
|
||||||
this.upElementObserver()
|
this.upElementObserver()
|
||||||
|
this.downElementObserver()
|
||||||
|
await this.updateComplete
|
||||||
this.viewElement.scrollTop = this.viewElement.scrollHeight + 50
|
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) {
|
_getOldMessage(_scrollElement) {
|
||||||
let listOfOldMessages = this.getOldMessage(_scrollElement)
|
this.getOldMessage(_scrollElement)
|
||||||
|
|
||||||
if (listOfOldMessages) {
|
|
||||||
this.renderOldMessages(listOfOldMessages)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_upObserverhandler(entries) {
|
_upObserverhandler(entries) {
|
||||||
if (entries[0].isIntersecting) {
|
if (entries[0].isIntersecting) {
|
||||||
let _scrollElement = entries[0].target.nextElementSibling
|
let _scrollElement = entries[0].target.nextElementSibling
|
||||||
|
console.log({ _scrollElement })
|
||||||
this._getOldMessage(_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() {
|
upElementObserver() {
|
||||||
const options = {
|
const options = {
|
||||||
root: this.viewElement,
|
root: this.viewElement,
|
||||||
@ -307,6 +287,475 @@ class ChatScroller extends LitElement {
|
|||||||
const observer = new IntersectionObserver(this._upObserverhandler, options)
|
const observer = new IntersectionObserver(this._upObserverhandler, options)
|
||||||
observer.observe(this.upObserverElement)
|
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)
|
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() {
|
firstUpdated() {
|
||||||
|
|
||||||
this.changeTheme()
|
this.changeTheme()
|
||||||
this.changeLanguage()
|
|
||||||
|
|
||||||
const stopKeyEventPropagation = (e) => {
|
const stopKeyEventPropagation = (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -95,8 +95,6 @@ class LevelFounder extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
|
||||||
this.changeLanguage()
|
|
||||||
this.checkAddressInfo()
|
this.checkAddressInfo()
|
||||||
|
|
||||||
window.addEventListener('storage', () => {
|
window.addEventListener('storage', () => {
|
||||||
|
@ -246,8 +246,6 @@ class NameMenu extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
|
||||||
this.changeLanguage()
|
|
||||||
this.getChatBlockedAdresses()
|
this.getChatBlockedAdresses()
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user