2022-09-06 19:26:43 -04:00
|
|
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
|
|
|
import * as tfrpc from '/static/tfrpc.js';
|
|
|
|
import * as tfutils from './tf-utils.js';
|
|
|
|
import * as emojis from './emojis.js';
|
|
|
|
import {styles} from './tf-styles.js';
|
|
|
|
|
|
|
|
class TfMessageElement extends LitElement {
|
|
|
|
static get properties() {
|
|
|
|
return {
|
|
|
|
whoami: {type: String},
|
|
|
|
message: {type: Object},
|
|
|
|
users: {type: Object},
|
|
|
|
reply: {type: Boolean},
|
|
|
|
raw: {type: Boolean},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static styles = styles;
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
let self = this;
|
|
|
|
this.whoami = null;
|
|
|
|
this.message = {};
|
|
|
|
this.users = {};
|
|
|
|
this.reply = false;
|
|
|
|
this.raw = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
show_reply() {
|
|
|
|
this.reply = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
render_votes() {
|
|
|
|
function normalize_expression(expression) {
|
|
|
|
if (expression === 'Like' || !expression) {
|
|
|
|
return '👍';
|
2022-09-09 22:56:15 -04:00
|
|
|
} else if (expression === 'Unlike') {
|
|
|
|
return '👎';
|
|
|
|
} else if (expression === 'heart') {
|
|
|
|
return '❤️';
|
2022-09-06 19:26:43 -04:00
|
|
|
} else {
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return html`<div>${(this.message.votes || []).map(vote => html`<span title="${this.users[vote.author]?.name ?? vote.author}">${normalize_expression(vote.content.vote.expression)}</span>`)}</div>`;
|
|
|
|
}
|
|
|
|
|
|
|
|
render_raw() {
|
|
|
|
return html`<div style="white-space: pre-wrap">${JSON.stringify(this.message, null, 2)}</div>`
|
|
|
|
}
|
|
|
|
|
|
|
|
vote(emoji) {
|
|
|
|
let reaction = emoji.emoji;
|
|
|
|
let message = this.message.id;
|
|
|
|
if (confirm('Are you sure you want to react with ' + reaction + ' to ' + message + '?')) {
|
|
|
|
tfrpc.rpc.appendMessage(
|
|
|
|
this.whoami,
|
|
|
|
{
|
|
|
|
type: 'vote',
|
|
|
|
vote: {
|
|
|
|
link: message,
|
|
|
|
value: 1,
|
|
|
|
expression: reaction,
|
|
|
|
},
|
|
|
|
}).catch(function(error) {
|
|
|
|
alert(error?.message);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
react(event) {
|
|
|
|
emojis.picker(x => this.vote(x));
|
|
|
|
}
|
|
|
|
|
2022-09-14 19:33:57 -04:00
|
|
|
render_mention(mention) {
|
|
|
|
if (mention.link?.startsWith('&') &&
|
|
|
|
mention.type?.startsWith('image/')) {
|
|
|
|
return html`
|
|
|
|
<img src=${'/' + mention.link + '/view'} style="max-width: 128px; max-height: 128px" title=${mention.name}>
|
|
|
|
`;
|
|
|
|
} else if (mention.link?.startsWith('&') &&
|
|
|
|
mention.name?.startsWith('audio:')) {
|
|
|
|
return html`
|
|
|
|
<audio controls style="height: 32px">
|
|
|
|
<source src=${'/' + mention.link + '/view'}></source>
|
|
|
|
</audio>
|
|
|
|
`;
|
|
|
|
} else if (mention.link?.startsWith('%') || mention.link?.startsWith('@')) {
|
|
|
|
return html` <a href=${'#' + encodeURIComponent(mention.link)}>${mention.name}</a>`;
|
|
|
|
} else if (mention.link?.startsWith('#')) {
|
|
|
|
return html` <a href=${'#q=' + encodeURIComponent(mention.link)}>${mention.link}</a>`;
|
|
|
|
} else {
|
|
|
|
return html`<pre>${JSON.stringify(mention)}</pre>`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render_mentions() {
|
|
|
|
if (this.message?.content?.mentions?.length) {
|
|
|
|
let self = this;
|
|
|
|
return html`
|
|
|
|
<fieldset style="background-color: rgba(0, 0, 0, 0.1); padding: 0.5em; border: 1px solid black">
|
|
|
|
<legend>Mentions</legend>
|
|
|
|
${(this.message?.content?.mentions || []).map(x => self.render_mention(x))}
|
|
|
|
</fieldset>
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-06 19:26:43 -04:00
|
|
|
render() {
|
|
|
|
let content = this.message?.content;
|
|
|
|
let self = this;
|
|
|
|
let raw_button = this.raw ?
|
|
|
|
html`<input type="button" value="Message" @click=${() => self.raw = false}></input>` :
|
|
|
|
html`<input type="button" value="Raw" @click=${() => self.raw = true}></input>`;
|
|
|
|
function small_frame(inner) {
|
|
|
|
return html`
|
|
|
|
<div style="border: 1px solid black; background-color: rgba(255, 255, 255, 0.1); margin-top: 8px; padding: 16px; display: inline-block">
|
|
|
|
<tf-user id=${self.message.author} .users=${self.users}></tf-user>
|
|
|
|
<span style="padding-right: 8px"><a target="_top" href=${'#' + self.message.id}>%</a> ${new Date(self.message.timestamp).toLocaleString()}</span>
|
|
|
|
${raw_button}
|
|
|
|
${self.raw ? self.render_raw() : inner}
|
|
|
|
${self.render_votes()}
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
}
|
|
|
|
if (this.message.placeholder) {
|
|
|
|
return html`
|
|
|
|
<div style="border: 1px solid black; background-color: rgba(255, 255, 255, 0.1); margin-top: 8px; padding: 16px">
|
|
|
|
${this.message.id} (placeholder)
|
|
|
|
<div>${this.render_votes()}</div>
|
|
|
|
${(this.message.child_messages || []).map(x => html`
|
|
|
|
<tf-message .message=${x} whoami=${this.whoami} .users=${this.users}></tf-message>
|
|
|
|
`)}
|
|
|
|
</div>`;
|
|
|
|
} else if (content.type == 'about') {
|
|
|
|
return small_frame(html`
|
|
|
|
<div style="font-weight: bold">Updated profile:</div>
|
|
|
|
<pre style="white-space: pre-wrap">${JSON.stringify(content, null, 2)}</pre>
|
|
|
|
`);
|
|
|
|
} else if (content.type == 'contact') {
|
|
|
|
return small_frame(html`
|
|
|
|
<div>
|
|
|
|
is now
|
|
|
|
${
|
|
|
|
content.blocking === true ? 'blocking' :
|
|
|
|
content.blocking === false ? 'unblocking' :
|
|
|
|
content.following === true ? 'following' :
|
|
|
|
content.following === false ? 'unfollowing' :
|
|
|
|
'?'
|
|
|
|
}
|
|
|
|
<tf-user id=${this.message.content.contact} .users=${this.users}></tf-user>
|
|
|
|
</div>
|
|
|
|
`);
|
|
|
|
} else if (content.type == 'post') {
|
|
|
|
let reply = this.reply ? html`
|
|
|
|
<tf-compose
|
|
|
|
?enabled=${this.reply}
|
|
|
|
whoami=${this.whoami}
|
|
|
|
.users=${this.users}
|
|
|
|
root=${this.message.content.root || this.message.id}
|
|
|
|
branch=${this.message.id}
|
|
|
|
@tf-discard=${() => this.reply = false}></tf-compose>
|
|
|
|
` : html`
|
|
|
|
<input type="button" value="Reply" @click=${this.show_reply}></input>
|
|
|
|
`;
|
|
|
|
let self = this;
|
|
|
|
let body = this.raw ?
|
|
|
|
this.render_raw() :
|
|
|
|
unsafeHTML(tfutils.markdown(content.text));
|
|
|
|
return html`
|
|
|
|
<style>
|
2022-09-09 22:56:15 -04:00
|
|
|
code {
|
|
|
|
white-space: pre-wrap;
|
|
|
|
overflow-wrap: break-word;
|
|
|
|
}
|
2022-09-06 19:26:43 -04:00
|
|
|
img {
|
|
|
|
max-width: 100%;
|
|
|
|
height: auto;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<div style="border: 1px solid black; background-color: rgba(255, 255, 255, 0.1); margin-top: 8px; padding: 16px">
|
|
|
|
<div style="display: flex; flex-direction: row">
|
|
|
|
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
|
|
|
|
<span style="flex: 1"></span>
|
|
|
|
<span style="padding-right: 8px"><a target="_top" href=${'#' + self.message.id}>%</a> ${new Date(this.message.timestamp).toLocaleString()}</span>
|
|
|
|
<span>${raw_button}</span>
|
|
|
|
</div>
|
|
|
|
<div>${body}</div>
|
2022-09-14 19:33:57 -04:00
|
|
|
${this.render_mentions()}
|
2022-09-06 19:26:43 -04:00
|
|
|
${this.render_votes()}
|
|
|
|
<div>
|
|
|
|
${reply}
|
|
|
|
<input type="button" value="React" @click=${this.react}></input>
|
|
|
|
</div>
|
|
|
|
${(this.message.child_messages || []).map(x => html`<tf-message .message=${x} whoami=${this.whoami} .users=${this.users}></tf-message>`)}
|
|
|
|
</div>
|
|
|
|
`;
|
|
|
|
} else if (typeof(this.message.content) == 'string') {
|
|
|
|
return small_frame(html`<span>🔒</span>`);
|
|
|
|
} else {
|
|
|
|
return small_frame(this.render_raw());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
customElements.define('tf-message', TfMessageElement);
|