Add files via upload

This commit is contained in:
AlphaX-Projects 2022-04-05 07:54:26 -07:00 committed by GitHub
parent 8bc397b18e
commit d8464855b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 260 additions and 33 deletions

View File

@ -0,0 +1,103 @@
import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import snackbar from './snackbar.js'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@material/mwc-snackbar'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class BlockAddress extends LitElement {
static get properties() {
return {
toblockaddress: { type: String, attribute: true },
chatBlockedAdresses: { type: Array }
}
}
static get styles() {
return css`
* {
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
--mdc-dialog-content-ink-color: var(--black);
--mdc-theme-surface: var(--white);
--mdc-theme-text-primary-on-background: var(--black);
}
`
}
constructor() {
super()
this.chatBlockedAdresses = []
}
render() {
return html`
<mwc-button dense unelevated label="block" icon="voice_over_off" @click="${() => this.chatBlockAddress()}"></mwc-button>
`
}
firstUpdated() {
this.getChatBlockedAdresses()
setInterval(() => {
this.getChatBlockedAdresses();
}, 60000)
}
updated(changedProps) {
}
async getChatBlockedAdresses() {
const chatBlockedAdresses = await parentEpml.request('apiCall', {
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`
})
this.chatBlockedAdresses = chatBlockedAdresses
}
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)
snackbar.add({
labelText: `Success blocked this user.`,
dismiss: true
})
} else {
snackbar.add({
labelText: `Error occurred when trying to block this user. Please try again.`,
dismiss: true
})
}
return ret
}
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey;
return apiKey;
}
}
window.customElements.define('block-address', BlockAddress)

View File

@ -99,7 +99,7 @@ class ChatMessage extends LitElement {
<span class="message-data-name">${this.message.sender}</span> &nbsp; <span class="message-data-name">${this.message.sender}</span> &nbsp;
<span class="message-data-time">10:10 AM, Today</span> <span class="message-data-time">10:10 AM, Today</span>
</div> </div>
<div class="message ${this.message.sender === this.selectedAddress.address ? "my-message float-right" : "other-message"}"> <div class="message ${this.message.sender === this.selectedAddress.address ? "my-message float-right" : "other-message float-left"}">
${this.message.decodedMessage} ${this.message.decodedMessage}
</div> </div>
</li> </li>

View File

@ -1,13 +1,19 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { escape, unescape } from 'html-escaper'; import { escape, unescape } from 'html-escaper';
import { inputKeyCodes } from '../../utils/keyCodes.js' import { inputKeyCodes } from '../../utils/keyCodes.js'
import './ChatScroller.js' import './ChatScroller.js'
import './BlockAddress.js'
import './TimeAgo.js' import './TimeAgo.js'
import { EmojiPicker } from 'emoji-picker-js'; import { EmojiPicker } from 'emoji-picker-js';
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
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 ChatPage extends LitElement { class ChatPage extends LitElement {
@ -120,15 +126,11 @@ class ChatPage extends LitElement {
} }
render() { render() {
// TODO: Build a nice preloader for loading messages...
return html` return html`
${this.isLoadingMessages ? html`<h1>Loading Messages...</h1>` : this.renderChatScroller(this._initialMessages)} ${this.isLoadingMessages ? html`<h1>Loading Messages...</h1>` : this.renderChatScroller(this._initialMessages)}
<div class="chat-text-area"> <div class="chat-text-area">
<div class="typing-area"> <div class="typing-area">
<textarea style="color: var(--black);" tabindex='1' ?autofocus=${true} ?disabled=${this.isLoading || this.isLoadingMessages} id="messageBox" rows="1"></textarea> <textarea style="color: var(--black);" tabindex='1' ?autofocus=${true} ?disabled=${this.isLoading || this.isLoadingMessages} id="messageBox" rows="1"></textarea>
<iframe class="chat-editor" id="_chatEditorDOM" tabindex="-1"></iframe> <iframe class="chat-editor" id="_chatEditorDOM" tabindex="-1"></iframe>
<button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}> <button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}>
${this.isLoading === false ? html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg">` : html`<paper-spinner-lite active></paper-spinner-lite>`} ${this.isLoading === false ? html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg">` : html`<paper-spinner-lite active></paper-spinner-lite>`}
@ -326,6 +328,7 @@ class ChatPage extends LitElement {
*/ */
chatMessageTemplate(messageObj) { chatMessageTemplate(messageObj) {
let avatarImg = ''; let avatarImg = '';
let blockButton = '';
if (messageObj.senderName) { if (messageObj.senderName) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
@ -333,11 +336,18 @@ class ChatPage extends LitElement {
avatarImg = `<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`; avatarImg = `<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`;
} }
if (messageObj.sender === this.selectedAddress.address) {
blockButton = ``
} else {
blockButton = `<block-address toblockaddress="${messageObj.sender}"></block-address>`
}
return ` return `
<li class="clearfix"> <li class="clearfix">
<div class="message-data ${messageObj.sender === this.selectedAddress.address ? "align-right" : ""}"> <div class="message-data ${messageObj.sender === this.selectedAddress.address ? "align-right" : ""}">
<span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span> <span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span>
<span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span> <span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span>
<span class="message-data-block">${blockButton}</span>
</div> </div>
<div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.selectedAddress.address ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div> <div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.selectedAddress.address ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div>
<div class="message ${messageObj.sender === this.selectedAddress.address ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(escape(messageObj.decodedMessage))}</div> <div class="message ${messageObj.sender === this.selectedAddress.address ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(escape(messageObj.decodedMessage))}</div>
@ -990,7 +1000,6 @@ class ChatPage extends LitElement {
this.chatEditor = new ChatEditor(editorConfig); this.chatEditor = new ChatEditor(editorConfig);
} }
} }
window.customElements.define('chat-page', ChatPage) window.customElements.define('chat-page', ChatPage)

View File

@ -1,4 +1,14 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import './BlockAddress.js'
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 { class ChatScroller extends LitElement {
static get properties() { static get properties() {
@ -64,6 +74,17 @@ class ChatScroller extends LitElement {
padding-left: 6px; padding-left: 6px;
} }
.message-data-block {
color: #03a9f4;
font-size: 16px;
padding-left: 6px;
}
.blockicon {
color: #03a9f4;
--mdc-icon-size: 16px;
}
.message { .message {
color: black; color: black;
padding: 12px 10px; padding: 12px 10px;
@ -153,7 +174,6 @@ class ChatScroller extends LitElement {
constructor() { constructor() {
super() super()
this.messages = [] this.messages = []
this._upObserverhandler = this._upObserverhandler.bind(this) this._upObserverhandler = this._upObserverhandler.bind(this)
this.isLoading = false this.isLoading = false
@ -162,17 +182,29 @@ class ChatScroller extends LitElement {
render() { render() {
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> <div id="downObserver"></div>
</ul> </ul>
` `
} }
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.viewElement.scrollTop = this.viewElement.scrollHeight + 50
}
chatMessageTemplate(messageObj) { chatMessageTemplate(messageObj) {
let avatarImg = ''; let avatarImg = '';
let blockButton = '';
if (messageObj.senderName) { if (messageObj.senderName) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
@ -180,11 +212,18 @@ class ChatScroller extends LitElement {
avatarImg = `<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`; 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) {
blockButton = ``
} else {
blockButton = `<block-address toblockaddress="${messageObj.sender}"></block-address>`
}
return ` return `
<li class="clearfix"> <li class="clearfix">
<div class="message-data ${messageObj.sender === this.myAddress ? "align-right" : ""}"> <div class="message-data ${messageObj.sender === this.myAddress ? "align-right" : ""}">
<span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span> <span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span>
<span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span> <span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span>
<span class="message-data-block">${blockButton}</span>
</div> </div>
<div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.myAddress ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div> <div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.myAddress ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div>
<div id="messageContent" class="message ${messageObj.sender === this.myAddress ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(this.escapeHTML(messageObj.decodedMessage))}</div> <div id="messageContent" class="message ${messageObj.sender === this.myAddress ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(this.escapeHTML(messageObj.decodedMessage))}</div>
@ -193,7 +232,6 @@ class ChatScroller extends LitElement {
} }
renderChatMessages(messages) { renderChatMessages(messages) {
messages.forEach(message => { messages.forEach(message => {
const li = document.createElement('li'); const li = document.createElement('li');
li.innerHTML = this.chatMessageTemplate(message); li.innerHTML = this.chatMessageTemplate(message);
@ -203,7 +241,6 @@ class ChatScroller extends LitElement {
} }
renderOldMessages(listOfOldMessages) { renderOldMessages(listOfOldMessages) {
let { oldMessages, scrollElement } = listOfOldMessages; let { oldMessages, scrollElement } = listOfOldMessages;
let _oldMessages = oldMessages.reverse(); let _oldMessages = oldMessages.reverse();
@ -217,7 +254,6 @@ class ChatScroller extends LitElement {
} }
_getOldMessage(_scrollElement) { _getOldMessage(_scrollElement) {
let listOfOldMessages = this.getOldMessage(_scrollElement) let listOfOldMessages = this.getOldMessage(_scrollElement)
if (listOfOldMessages) { if (listOfOldMessages) {
@ -226,7 +262,6 @@ class ChatScroller extends LitElement {
} }
_upObserverhandler(entries) { _upObserverhandler(entries) {
if (entries[0].isIntersecting) { if (entries[0].isIntersecting) {
let _scrollElement = entries[0].target.nextElementSibling let _scrollElement = entries[0].target.nextElementSibling
@ -244,21 +279,6 @@ 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)
} }
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.viewElement.scrollTop = this.viewElement.scrollHeight + 50;
}
} }
window.customElements.define('chat-scroller', ChatScroller) window.customElements.define('chat-scroller', ChatScroller)

View File

@ -6,6 +6,7 @@ import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/grid'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -209,7 +210,7 @@ class ChatWelcomePage extends LitElement {
<div class="start-chat" @click=${() => this.shadowRoot.querySelector('#startSecondChatDialog').show()}>New Private Message</div> <div class="start-chat" @click=${() => this.shadowRoot.querySelector('#startSecondChatDialog').show()}>New Private Message</div>
</div> </div>
</div> </div>
<!-- Start Chatting Dialog --> <!-- Start Chatting Dialog -->
<mwc-dialog id="startSecondChatDialog" scrimClickAction="${this.isLoading ? '' : 'close'}"> <mwc-dialog id="startSecondChatDialog" scrimClickAction="${this.isLoading ? '' : 'close'}">
<div style="text-align:center"> <div style="text-align:center">
@ -292,7 +293,6 @@ class ChatWelcomePage extends LitElement {
} }
_sendMessage() { _sendMessage() {
this.isLoading = true this.isLoading = true
const recipient = this.shadowRoot.getElementById('sendTo').value const recipient = this.shadowRoot.getElementById('sendTo').value
@ -465,6 +465,17 @@ class ChatWelcomePage extends LitElement {
_textArea(e) { _textArea(e) {
if (e.keyCode === 13 && !e.shiftKey) this._sendMessage() if (e.keyCode === 13 && !e.shiftKey) this._sendMessage()
} }
isEmptyArray(arr) {
if (!arr) { return true }
return arr.length === 0
}
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey;
return apiKey;
}
} }
window.customElements.define('chat-welcome-page', ChatWelcomePage) window.customElements.define('chat-welcome-page', ChatWelcomePage)

View File

@ -0,0 +1,84 @@
import { LitElement, html, css } from 'lit'
import '@material/mwc-snackbar'
let queueElement
class SnackQueue extends LitElement {
static get properties() {
return {
busy: {
type: Boolean,
attribute: 'busy',
reflectToAttribute: true
},
currentSnack: {
type: Object,
attribute: 'current-snack',
reflectToAttribute: true
},
_queue: {
type: Array
},
_labelText: { type: String },
_stacked: { type: Boolean },
_leading: { type: Boolean },
_closeOnEscape: { type: Boolean },
_timeoutMs: { type: Number },
action: {},
_dismiss: {},
_dismissIcon: { type: String }
}
}
static get styles() {
return css``
}
constructor() {
super()
this._queue = []
this.busy = false
this._timeoutMs = 5000
}
render() {
return html`
<mwc-snackbar id="snack" labelText="${this._labelText}" ?stacked=${this._stacked} ?leading=${this._leading} ?closeOnEscape=${this._closeOnEscape} timeoutMs=${this._timeoutMs}>
${this._action}
${this._dismiss ? html`
<mwc-icon-button icon="${this._dismissIcon}" slot="dismiss"></mwc-icon-button>
` : ''}
</mwc-snackbar>
`
}
firstUpdated() {
this._snackbar = this.shadowRoot.getElementById('snack')
}
_shift() {
if (this.busy || this._queue.length === 0) return
const item = this._queue.shift()
this._labelText = item.labelText || ''
this._action = item.action || ''
this._dismiss = item.dismiss || false
this._dismissIcon = item.dismissIcon || 'close'
this._leading = !!item.leading
this._closeOnEscape = (item.closeOnEscape && item.closeOnEscape !== false) // JSON.parse maybe needs to be compared to 'false'...in which case no need for complex expression
this._timeoutMs = (item.timeoutMs >= 4000 && item.timeoutMs <= 10000) ? item.timeoutMs : 5000
this._snackbar.show()
}
add(item) {
this._queue.push(item)
this._shift()
}
}
window.customElements.define('snack-queue', SnackQueue)
const queueNode = document.createElement('snack-queue')
queueNode.id = 'queue-node'
queueNode.loadingMessage = ''
queueElement = document.body.appendChild(queueNode)
export default queueElement