2021-03-12 09:58:17 +01:00
|
|
|
import './message-actions.js';
|
|
|
|
import './message-body.js';
|
2021-03-24 11:59:09 +01:00
|
|
|
import 'shared/components/dropdown.js';
|
|
|
|
import 'shared/registry';
|
2021-02-22 20:20:19 +01:00
|
|
|
import MessageVersionsModal from 'modals/message-versions.js';
|
2021-02-09 11:14:06 +01:00
|
|
|
import OccupantModal from 'modals/occupant.js';
|
|
|
|
import UserDetailsModal from 'modals/user-details.js';
|
2020-05-15 14:33:31 +02:00
|
|
|
import dayjs from 'dayjs';
|
2020-08-12 17:57:39 +02:00
|
|
|
import filesize from 'filesize';
|
2021-03-05 15:00:01 +01:00
|
|
|
import tpl_message from './templates/message.js';
|
2021-02-22 20:20:19 +01:00
|
|
|
import tpl_spinner from 'templates/spinner.js';
|
2021-03-24 11:59:09 +01:00
|
|
|
import { CustomElement } from 'shared/components/element.js';
|
2021-02-22 20:20:19 +01:00
|
|
|
import { __ } from 'i18n';
|
2020-12-03 13:40:30 +01:00
|
|
|
import { _converse, api, converse } from '@converse/headless/core';
|
2020-05-15 14:33:31 +02:00
|
|
|
import { html } from 'lit-element';
|
2021-03-24 11:59:09 +01:00
|
|
|
import { renderAvatar } from 'shared/directives/avatar';
|
2020-05-15 14:33:31 +02:00
|
|
|
|
|
|
|
const { Strophe } = converse.env;
|
|
|
|
const u = converse.env.utils;
|
|
|
|
|
|
|
|
|
2020-07-01 21:45:18 +02:00
|
|
|
export default class Message extends CustomElement {
|
2020-05-15 14:33:31 +02:00
|
|
|
|
|
|
|
static get properties () {
|
|
|
|
return {
|
2021-04-15 17:23:53 +02:00
|
|
|
jid: { type: String },
|
|
|
|
mid: { type: String }
|
2020-05-15 14:33:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
if (this.show_spinner) {
|
|
|
|
return tpl_spinner();
|
|
|
|
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
|
|
|
return this.renderFileProgress();
|
2021-04-15 17:23:53 +02:00
|
|
|
} else if (['error', 'info'].includes(this.model.get('type'))) {
|
2020-05-15 14:33:31 +02:00
|
|
|
return this.renderInfoMessage();
|
|
|
|
} else {
|
|
|
|
return this.renderChatMessage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-26 21:42:57 +02:00
|
|
|
connectedCallback () {
|
|
|
|
super.connectedCallback();
|
2021-04-15 17:23:53 +02:00
|
|
|
this.chatbox = _converse.chatboxes.get(this.jid);
|
|
|
|
this.model = this.chatbox.messages.get(this.mid);
|
|
|
|
|
|
|
|
this.listenTo(this.model, 'change', () => this.requestUpdate());
|
|
|
|
this.model.vcard && this.listenTo(this.model.vcard, 'change', () => this.requestUpdate());
|
|
|
|
|
|
|
|
if (this.model.get('type') === 'groupchat') {
|
|
|
|
if (this.model.occupant) {
|
|
|
|
this.listenTo(this.model.occupant, 'change', () => this.requestUpdate());
|
|
|
|
} else {
|
|
|
|
this.listenTo(this.model, 'occupantAdded', () => {
|
|
|
|
this.listenTo(this.model.occupant, 'change', () => this.requestUpdate())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getProps () {
|
|
|
|
return Object.assign(
|
|
|
|
this.model.toJSON(),
|
|
|
|
this.getDerivedMessageProps()
|
|
|
|
);
|
2020-09-26 21:42:57 +02:00
|
|
|
}
|
|
|
|
|
2020-05-15 14:33:31 +02:00
|
|
|
renderInfoMessage () {
|
|
|
|
const isodate = dayjs(this.model.get('time')).toISOString();
|
|
|
|
const i18n_retry = __('Retry');
|
|
|
|
return html`
|
2021-04-15 17:23:53 +02:00
|
|
|
<div class="message chat-info chat-${this.model.get('type')}"
|
2020-05-15 14:33:31 +02:00
|
|
|
data-isodate="${isodate}"
|
|
|
|
data-type="${this.data_name}"
|
|
|
|
data-value="${this.data_value}">
|
|
|
|
|
|
|
|
<div class="chat-info__message">
|
|
|
|
${ this.model.getMessageText() }
|
|
|
|
</div>
|
2021-04-15 17:23:53 +02:00
|
|
|
${ this.model.get('reason') ? html`<q class="reason">${this.model.get('reason')}</q>` : `` }
|
|
|
|
${ this.model.get('error_text') ? html`<q class="reason">${this.model.get('error_text')}</q>` : `` }
|
|
|
|
${ this.model.get('retry_event_id') ? html`<a class="retry" @click=${this.onRetryClicked}>${i18n_retry}</a>` : '' }
|
|
|
|
</div>`;
|
2020-05-15 14:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
renderFileProgress () {
|
2020-08-17 08:53:08 +02:00
|
|
|
const i18n_uploading = __('Uploading file:');
|
2020-05-15 14:33:31 +02:00
|
|
|
const filename = this.model.file.name;
|
|
|
|
const size = filesize(this.model.file.size);
|
|
|
|
return html`
|
|
|
|
<div class="message chat-msg">
|
2020-06-03 13:53:52 +02:00
|
|
|
${ renderAvatar(this.getAvatarData()) }
|
2020-05-15 14:33:31 +02:00
|
|
|
<div class="chat-msg__content">
|
|
|
|
<span class="chat-msg__text">${i18n_uploading} <strong>${filename}</strong>, ${size}</span>
|
2021-04-15 17:23:53 +02:00
|
|
|
<progress value="${this.model.get('progress')}"/>
|
2020-05-15 14:33:31 +02:00
|
|
|
</div>
|
|
|
|
</div>`;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderChatMessage () {
|
2021-04-15 17:23:53 +02:00
|
|
|
return tpl_message(this, this.getProps());
|
2020-05-15 14:33:31 +02:00
|
|
|
}
|
|
|
|
|
2020-06-04 14:27:51 +02:00
|
|
|
shouldShowAvatar () {
|
2021-04-15 17:23:53 +02:00
|
|
|
return api.settings.get('show_message_avatar') && !this.model.isMeCommand() && this.type !== 'headline';
|
2020-06-04 14:27:51 +02:00
|
|
|
}
|
|
|
|
|
2020-06-03 13:53:52 +02:00
|
|
|
getAvatarData () {
|
2020-06-04 15:34:06 +02:00
|
|
|
const image_type = this.model.vcard?.get('image_type') || _converse.DEFAULT_IMAGE_TYPE;
|
|
|
|
const image_data = this.model.vcard?.get('image') || _converse.DEFAULT_IMAGE;
|
2020-06-03 13:53:52 +02:00
|
|
|
const image = "data:" + image_type + ";base64," + image_data;
|
|
|
|
return {
|
|
|
|
'classes': 'chat-msg__avatar',
|
|
|
|
'height': 36,
|
|
|
|
'width': 36,
|
|
|
|
image,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-05 15:00:01 +01:00
|
|
|
onUnfurlAnimationEnd () {
|
|
|
|
if (this.model.get('url_preview_transition') === 'fade-out') {
|
|
|
|
this.model.save({
|
|
|
|
'hide_url_previews': !this.model.get('hide_url_previews'),
|
|
|
|
'url_preview_transition': 'fade-in'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 14:33:31 +02:00
|
|
|
async onRetryClicked () {
|
|
|
|
this.show_spinner = true;
|
2021-04-15 17:23:53 +02:00
|
|
|
this.requestUpdate();
|
|
|
|
await api.trigger(this.model.get('retry_event_id'), {'synchronous': true});
|
2020-05-15 14:33:31 +02:00
|
|
|
this.model.destroy();
|
|
|
|
this.parentElement.removeChild(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
isFollowup () {
|
|
|
|
const messages = this.model.collection.models;
|
|
|
|
const idx = messages.indexOf(this.model);
|
|
|
|
const prev_model = idx ? messages[idx-1] : null;
|
|
|
|
if (prev_model === null) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-04-15 17:23:53 +02:00
|
|
|
const date = dayjs(this.model.get('time'));
|
|
|
|
return this.model.get('from') === prev_model.get('from') &&
|
|
|
|
!this.model.isMeCommand() &&
|
2020-05-15 14:33:31 +02:00
|
|
|
!prev_model.isMeCommand() &&
|
2021-04-15 17:23:53 +02:00
|
|
|
this.model.get('type') !== 'info' &&
|
2020-05-15 14:33:31 +02:00
|
|
|
prev_model.get('type') !== 'info' &&
|
|
|
|
date.isBefore(dayjs(prev_model.get('time')).add(10, 'minutes')) &&
|
2021-04-15 17:23:53 +02:00
|
|
|
!!this.model.get('is_encrypted') === !!prev_model.get('is_encrypted');
|
|
|
|
}
|
|
|
|
|
|
|
|
isRetracted () {
|
|
|
|
return this.model.get('retracted') || this.model.get('moderated') === 'retracted';
|
|
|
|
}
|
|
|
|
|
|
|
|
hasMentions () {
|
|
|
|
const is_groupchat = this.model.get('type') === 'groupchat';
|
|
|
|
return is_groupchat && this.model.get('sender') === 'them' && this.chatbox.isUserMentioned(this.model);
|
|
|
|
}
|
|
|
|
|
|
|
|
getOccupantAffiliation () {
|
|
|
|
return this.model.occupant?.get('affiliation');
|
|
|
|
}
|
|
|
|
|
|
|
|
getOccupantRole () {
|
|
|
|
return this.model.occupant?.get('role');
|
2020-05-15 14:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
getExtraMessageClasses () {
|
|
|
|
const extra_classes = [
|
2020-06-04 15:17:47 +02:00
|
|
|
this.isFollowup() ? 'chat-msg--followup' : null,
|
2021-04-15 17:23:53 +02:00
|
|
|
this.model.get('is_delayed') ? 'delayed' : null,
|
|
|
|
this.model.isMeCommand() ? 'chat-msg--action' : null,
|
|
|
|
this.isRetracted() ? 'chat-msg--retracted' : null,
|
|
|
|
this.model.get('type'),
|
2020-06-04 15:17:47 +02:00
|
|
|
this.shouldShowAvatar() ? 'chat-msg--with-avatar' : null,
|
|
|
|
].map(c => c);
|
|
|
|
|
2021-04-15 17:23:53 +02:00
|
|
|
if (this.model.get('type') === 'groupchat') {
|
|
|
|
extra_classes.push(this.getOccupantRole() ?? '');
|
|
|
|
extra_classes.push(this.getOccupantAffiliation() ?? '');
|
|
|
|
if (this.model.get('sender') === 'them' && this.hasMentions()) {
|
2020-05-15 14:33:31 +02:00
|
|
|
extra_classes.push('mentioned');
|
|
|
|
}
|
|
|
|
}
|
2021-04-15 17:23:53 +02:00
|
|
|
this.model.get('correcting') && extra_classes.push('correcting');
|
2020-05-15 14:33:31 +02:00
|
|
|
return extra_classes.filter(c => c).join(" ");
|
|
|
|
}
|
|
|
|
|
2021-04-15 17:23:53 +02:00
|
|
|
getDerivedMessageProps () {
|
2021-04-23 10:59:50 +02:00
|
|
|
const format = api.settings.get('time_format');
|
2021-04-15 17:23:53 +02:00
|
|
|
return {
|
2021-04-23 10:59:50 +02:00
|
|
|
'pretty_time': dayjs(this.model.get('edited') || this.model.get('time')).format(format),
|
2021-04-15 17:23:53 +02:00
|
|
|
'has_mentions': this.hasMentions(),
|
|
|
|
'hats': _converse.getHats(this.model),
|
|
|
|
'is_first_unread': this.chatbox.get('first_unread_id') === this.model.get('id'),
|
|
|
|
'is_me_message': this.model.isMeCommand(),
|
|
|
|
'is_retracted': this.isRetracted(),
|
|
|
|
'username': this.model.getDisplayName(),
|
|
|
|
'should_show_avatar': this.shouldShowAvatar(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 14:33:31 +02:00
|
|
|
getRetractionText () {
|
2021-04-15 17:23:53 +02:00
|
|
|
if (this.model.get('type') === 'groupchat' && this.model.get('moderated_by')) {
|
|
|
|
const retracted_by_mod = this.model.get('moderated_by');
|
2020-05-15 14:33:31 +02:00
|
|
|
const chatbox = this.model.collection.chatbox;
|
|
|
|
if (!this.model.mod) {
|
|
|
|
this.model.mod =
|
|
|
|
chatbox.occupants.findOccupant({'jid': retracted_by_mod}) ||
|
|
|
|
chatbox.occupants.findOccupant({'nick': Strophe.getResourceFromJid(retracted_by_mod)});
|
|
|
|
}
|
|
|
|
const modname = this.model.mod ? this.model.mod.getDisplayName() : 'A moderator';
|
|
|
|
return __('%1$s has removed this message', modname);
|
|
|
|
} else {
|
|
|
|
return __('%1$s has removed this message', this.model.getDisplayName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
renderRetraction () {
|
2021-04-15 17:23:53 +02:00
|
|
|
const retraction_text = this.isRetracted() ? this.getRetractionText() : null;
|
2020-05-15 14:33:31 +02:00
|
|
|
return html`
|
|
|
|
<div>${retraction_text}</div>
|
2021-04-15 17:23:53 +02:00
|
|
|
${ this.model.get('moderation_reason') ?
|
|
|
|
html`<q class="chat-msg--retracted__reason">${this.model.get('moderation_reason')}</q>` : '' }
|
2020-05-15 14:33:31 +02:00
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderMessageText () {
|
2020-08-17 08:53:08 +02:00
|
|
|
const i18n_edited = __('This message has been edited');
|
|
|
|
const i18n_show = __('Show more');
|
2021-04-15 17:23:53 +02:00
|
|
|
const is_groupchat_message = (this.model.get('type') === 'groupchat');
|
2020-08-17 08:53:08 +02:00
|
|
|
const i18n_show_less = __('Show less');
|
|
|
|
|
2020-05-15 14:33:31 +02:00
|
|
|
const tpl_spoiler_hint = html`
|
|
|
|
<div class="chat-msg__spoiler-hint">
|
2021-04-15 17:23:53 +02:00
|
|
|
<span class="spoiler-hint">${this.model.get('spoiler_hint')}</span>
|
2020-05-15 14:33:31 +02:00
|
|
|
<a class="badge badge-info spoiler-toggle" href="#" @click=${this.toggleSpoilerMessage}>
|
2021-04-15 17:23:53 +02:00
|
|
|
<i class="fa ${this.model.get('is_spoiler_visible') ? 'fa-eye-slash' : 'fa-eye'}"></i>
|
|
|
|
${ this.model.get('is_spoiler_visible') ? i18n_show_less : i18n_show }
|
2020-05-15 14:33:31 +02:00
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
`;
|
2021-04-15 17:23:53 +02:00
|
|
|
const spoiler_classes = this.model.get('is_spoiler') ? `spoiler ${this.model.get('is_spoiler_visible') ? '' : 'hidden'}` : '';
|
|
|
|
const text = this.model.getMessageText();
|
2020-05-15 14:33:31 +02:00
|
|
|
return html`
|
2021-04-15 17:23:53 +02:00
|
|
|
${ this.model.get('is_spoiler') ? tpl_spoiler_hint : '' }
|
|
|
|
${ this.model.get('subject') ? html`<div class="chat-msg__subject">${this.model.get('subject')}</div>` : '' }
|
2020-06-11 17:03:59 +02:00
|
|
|
<span>
|
|
|
|
<converse-chat-message-body
|
2021-04-15 17:23:53 +02:00
|
|
|
class="chat-msg__text ${this.model.get('is_only_emojis') ? 'chat-msg__text--larger' : ''} ${spoiler_classes}"
|
2020-06-11 17:03:59 +02:00
|
|
|
.model="${this.model}"
|
2021-04-15 17:23:53 +02:00
|
|
|
?is_me_message="${this.model.isMeCommand()}"
|
2021-04-26 12:01:34 +02:00
|
|
|
?show_images="${api.settings.get('show_images_inline')}"
|
2021-04-15 17:23:53 +02:00
|
|
|
text="${text}"></converse-chat-message-body>
|
|
|
|
${ (this.model.get('received') && !this.model.isMeCommand() && !is_groupchat_message) ? html`<span class="fa fa-check chat-msg__receipt"></span>` : '' }
|
|
|
|
${ (this.model.get('edited')) ? html`<i title="${ i18n_edited }" class="fa fa-edit chat-msg__edit-modal" @click=${this.showMessageVersionsModal}></i>` : '' }
|
2020-06-11 17:03:59 +02:00
|
|
|
</span>
|
2021-04-15 17:23:53 +02:00
|
|
|
${ this.model.get('oob_url') ? html`<div class="chat-msg__media">${u.getOOBURLMarkup(_converse, this.model.get('oob_url'))}</div>` : '' }
|
|
|
|
<div class="chat-msg__error">${ this.model.get('error_text') || this.model.get('error') }</div>
|
2020-05-15 14:33:31 +02:00
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
2020-12-01 16:31:57 +01:00
|
|
|
showUserModal (ev) {
|
|
|
|
if (this.model.get('sender') === 'me') {
|
|
|
|
_converse.xmppstatusview.showProfileModal(ev);
|
2021-04-15 17:23:53 +02:00
|
|
|
} else if (this.model.get('type') === 'groupchat') {
|
2021-02-09 11:14:06 +01:00
|
|
|
ev.preventDefault();
|
|
|
|
api.modal.show(OccupantModal, { 'model': this.model.occupant }, ev);
|
2020-12-01 16:31:57 +01:00
|
|
|
} else {
|
2021-02-09 11:14:06 +01:00
|
|
|
ev.preventDefault();
|
|
|
|
const chatbox = this.model.collection.chatbox;
|
|
|
|
api.modal.show(UserDetailsModal, { model: chatbox }, ev);
|
2020-12-01 16:31:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 14:33:31 +02:00
|
|
|
showMessageVersionsModal (ev) {
|
|
|
|
ev.preventDefault();
|
2020-12-10 13:25:59 +01:00
|
|
|
api.modal.show(MessageVersionsModal, {'model': this.model}, ev);
|
2020-05-15 14:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
toggleSpoilerMessage (ev) {
|
|
|
|
ev?.preventDefault();
|
|
|
|
this.model.save({'is_spoiler_visible': !this.model.get('is_spoiler_visible')});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-01 21:45:18 +02:00
|
|
|
api.elements.define('converse-chat-message', Message);
|