Refactor message component to require less attributes
This commit is contained in:
parent
9e90b60a4f
commit
3558936b46
@ -422,14 +422,13 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it("shows an error message if the file is too large",
|
it("shows an error message if the file is too large",
|
||||||
mock.initConverse([], {}, async function (done, _converse) {
|
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
const IQ_ids = _converse.connection.IQ_ids;
|
const IQ_ids = _converse.connection.IQ_ids;
|
||||||
|
|
||||||
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
|
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
|
||||||
await u.waitUntil(() => _.filter(
|
await u.waitUntil(() => IQ_stanzas.filter(
|
||||||
IQ_stanzas,
|
|
||||||
iq => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
|
iq => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -42,11 +42,8 @@ window.addEventListener('converse-loaded', () => {
|
|||||||
const { u, sizzle, Strophe, dayjs, $iq, $msg, $pres } = converse.env;
|
const { u, sizzle, Strophe, dayjs, $iq, $msg, $pres } = converse.env;
|
||||||
|
|
||||||
mock.waitUntilDiscoConfirmed = async function (_converse, entity_jid, identities, features=[], items=[], type='info') {
|
mock.waitUntilDiscoConfirmed = async function (_converse, entity_jid, identities, features=[], items=[], type='info') {
|
||||||
const iq = await u.waitUntil(() => {
|
const sel = `iq[to="${entity_jid}"] query[xmlns="http://jabber.org/protocol/disco#${type}"]`;
|
||||||
return _converse.connection.IQ_stanzas.filter(
|
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(iq => sizzle(sel, iq).length).pop(), 300);
|
||||||
iq => sizzle(`iq[to="${entity_jid}"] query[xmlns="http://jabber.org/protocol/disco#${type}"]`, iq).length
|
|
||||||
).pop();
|
|
||||||
}, 300);
|
|
||||||
const stanza = $iq({
|
const stanza = $iq({
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'from': entity_jid,
|
'from': entity_jid,
|
||||||
|
@ -867,7 +867,7 @@ describe("A Chat Message", function () {
|
|||||||
expect(view.querySelector(`${nth_child(4)} .chat-msg__text`).textContent).toBe(
|
expect(view.querySelector(`${nth_child(4)} .chat-msg__text`).textContent).toBe(
|
||||||
"A delayed message, sent 5 minutes since we started");
|
"A delayed message, sent 5 minutes since we started");
|
||||||
|
|
||||||
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(5)))).toBe(true);
|
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(5)))).toBe(false);
|
||||||
expect(view.querySelector(`${nth_child(5)} .chat-msg__text`).textContent).toBe(
|
expect(view.querySelector(`${nth_child(5)} .chat-msg__text`).textContent).toBe(
|
||||||
"Another message 14 minutes since we started");
|
"Another message 14 minutes since we started");
|
||||||
|
|
||||||
@ -900,10 +900,10 @@ describe("A Chat Message", function () {
|
|||||||
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(4)))).toBe(false);
|
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(4)))).toBe(false);
|
||||||
expect(view.querySelector(`${nth_child(4)} .chat-msg__text`).textContent).toBe(
|
expect(view.querySelector(`${nth_child(4)} .chat-msg__text`).textContent).toBe(
|
||||||
"A carbon message 4 minutes later");
|
"A carbon message 4 minutes later");
|
||||||
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(5)))).toBe(false);
|
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(5)))).toBe(true);
|
||||||
expect(view.querySelector(`${nth_child(5)} .chat-msg__text`).textContent).toBe(
|
expect(view.querySelector(`${nth_child(5)} .chat-msg__text`).textContent).toBe(
|
||||||
"A delayed message, sent 5 minutes since we started");
|
"A delayed message, sent 5 minutes since we started");
|
||||||
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(6)))).toBe(true);
|
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(6)))).toBe(false);
|
||||||
expect(view.querySelector(`${nth_child(6)} .chat-msg__text`).textContent).toBe(
|
expect(view.querySelector(`${nth_child(6)} .chat-msg__text`).textContent).toBe(
|
||||||
"Another message 14 minutes since we started");
|
"Another message 14 minutes since we started");
|
||||||
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(7)))).toBe(true);
|
expect(u.hasClass('chat-msg--followup', view.querySelector(nth_child(7)))).toBe(true);
|
||||||
|
@ -6,48 +6,6 @@ import { _converse, api } from "@converse/headless/core";
|
|||||||
import { html } from 'lit-element';
|
import { html } from 'lit-element';
|
||||||
import { repeat } from 'lit-html/directives/repeat.js';
|
import { repeat } from 'lit-html/directives/repeat.js';
|
||||||
|
|
||||||
const tpl_message = (o) => html`
|
|
||||||
<converse-chat-message
|
|
||||||
.hats=${o.hats}
|
|
||||||
.model=${o.model}
|
|
||||||
?correcting=${o.correcting}
|
|
||||||
?editable=${o.editable}
|
|
||||||
?has_mentions=${o.has_mentions}
|
|
||||||
?is_delayed=${o.is_delayed}
|
|
||||||
?is_encrypted=${!!o.is_encrypted}
|
|
||||||
?is_first_unread=${o.is_first_unread}
|
|
||||||
?is_me_message=${o.is_me_message}
|
|
||||||
?is_only_emojis=${o.is_only_emojis}
|
|
||||||
?is_retracted=${o.is_retracted}
|
|
||||||
?is_spoiler=${o.is_spoiler}
|
|
||||||
?is_spoiler_visible=${o.is_spoiler_visible}
|
|
||||||
?retractable=${o.retractable}
|
|
||||||
edited=${o.edited || ''}
|
|
||||||
error=${o.error || ''}
|
|
||||||
error_text=${o.error_text || ''}
|
|
||||||
filename=${o.filename || ''}
|
|
||||||
filesize=${o.filesize || ''}
|
|
||||||
from=${o.from}
|
|
||||||
message_type=${o.type || ''}
|
|
||||||
moderated_by=${o.moderated_by || ''}
|
|
||||||
moderation_reason=${o.moderation_reason || ''}
|
|
||||||
msgid=${o.msgid}
|
|
||||||
occupant_affiliation=${o.model.occupant ? o.model.occupant.get('affiliation') : ''}
|
|
||||||
occupant_role=${o.model.occupant ? o.model.occupant.get('role') : ''}
|
|
||||||
oob_url=${o.oob_url || ''}
|
|
||||||
pretty_type=${o.pretty_type}
|
|
||||||
progress=${o.progress || 0 }
|
|
||||||
reason=${o.reason || ''}
|
|
||||||
received=${o.received || ''}
|
|
||||||
retry_event_id=${o.retry_event_id || ''}
|
|
||||||
sender=${o.sender}
|
|
||||||
spoiler_hint=${o.spoiler_hint || ''}
|
|
||||||
subject=${o.subject || ''}
|
|
||||||
time=${o.time}
|
|
||||||
unfurl_metadata=${o.unfurl_metadata}
|
|
||||||
username=${o.username}></converse-chat-message>
|
|
||||||
`;
|
|
||||||
|
|
||||||
|
|
||||||
// Return a TemplateResult indicating a new day if the passed in message is
|
// Return a TemplateResult indicating a new day if the passed in message is
|
||||||
// more than a day later than its predecessor.
|
// more than a day later than its predecessor.
|
||||||
@ -88,19 +46,6 @@ _converse.getHats = function (model) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getDerivedMessageProps (chatbox, model) {
|
|
||||||
const is_groupchat = model.get('type') === 'groupchat';
|
|
||||||
return {
|
|
||||||
'has_mentions': is_groupchat && model.get('sender') === 'them' && chatbox.isUserMentioned(model),
|
|
||||||
'hats': _converse.getHats(model),
|
|
||||||
'is_first_unread': chatbox.get('first_unread_id') === model.get('id'),
|
|
||||||
'is_me_message': model.isMeCommand(),
|
|
||||||
'is_retracted': model.get('retracted') || model.get('moderated') === 'retracted',
|
|
||||||
'username': model.getDisplayName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default class MessageHistory extends CustomElement {
|
export default class MessageHistory extends CustomElement {
|
||||||
|
|
||||||
static get properties () {
|
static get properties () {
|
||||||
@ -121,13 +66,10 @@ export default class MessageHistory extends CustomElement {
|
|||||||
}
|
}
|
||||||
const day = getDayIndicator(model);
|
const day = getDayIndicator(model);
|
||||||
const templates = day ? [day] : [];
|
const templates = day ? [day] : [];
|
||||||
const message = tpl_message(
|
const message = html`<converse-chat-message
|
||||||
Object.assign(
|
jid="${this.model.get('jid')}"
|
||||||
model.toJSON(),
|
mid="${model.get('id')}"></converse-chat-message>`
|
||||||
getDerivedMessageProps(this.model, model),
|
|
||||||
{ model }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return [...templates, message];
|
return [...templates, message];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import tpl_spinner from 'templates/spinner.js';
|
|||||||
import { CustomElement } from 'shared/components/element.js';
|
import { CustomElement } from 'shared/components/element.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { _converse, api, converse } from '@converse/headless/core';
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
import { getDerivedMessageProps } from './message-history';
|
|
||||||
import { html } from 'lit-element';
|
import { html } from 'lit-element';
|
||||||
import { renderAvatar } from 'shared/directives/avatar';
|
import { renderAvatar } from 'shared/directives/avatar';
|
||||||
|
|
||||||
@ -24,53 +23,19 @@ export default class Message extends CustomElement {
|
|||||||
|
|
||||||
static get properties () {
|
static get properties () {
|
||||||
return {
|
return {
|
||||||
correcting: { type: Boolean },
|
jid: { type: String },
|
||||||
editable: { type: Boolean },
|
mid: { type: String }
|
||||||
edited: { type: String },
|
|
||||||
error: { type: String },
|
|
||||||
error_text: { type: String },
|
|
||||||
from: { type: String },
|
|
||||||
has_mentions: { type: Boolean },
|
|
||||||
hats: { type: Array },
|
|
||||||
is_delayed: { type: Boolean },
|
|
||||||
is_encrypted: { type: Boolean },
|
|
||||||
is_first_unread: { type: Boolean },
|
|
||||||
is_me_message: { type: Boolean },
|
|
||||||
is_only_emojis: { type: Boolean },
|
|
||||||
is_retracted: { type: Boolean },
|
|
||||||
is_spoiler: { type: Boolean },
|
|
||||||
is_spoiler_visible: { type: Boolean },
|
|
||||||
message_type: { type: String },
|
|
||||||
model: { type: Object },
|
|
||||||
moderated_by: { type: String },
|
|
||||||
moderation_reason: { type: String },
|
|
||||||
msgid: { type: String },
|
|
||||||
occupant_affiliation: { type: String },
|
|
||||||
occupant_role: { type: String },
|
|
||||||
oob_url: { type: String },
|
|
||||||
progress: { type: Number },
|
|
||||||
reason: { type: String },
|
|
||||||
received: { type: String },
|
|
||||||
retractable: { type: Boolean },
|
|
||||||
retry_event_id: { type: String },
|
|
||||||
sender: { type: String },
|
|
||||||
show_spinner: { type: Boolean },
|
|
||||||
spoiler_hint: { type: String },
|
|
||||||
subject: { type: String },
|
|
||||||
time: { type: String },
|
|
||||||
unfurl_metadata: { type: String },
|
|
||||||
username: { type: String }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const format = api.settings.get('time_format');
|
const format = api.settings.get('time_format');
|
||||||
this.pretty_time = dayjs(this.edited || this.time).format(format);
|
this.pretty_time = dayjs(this.model.get('edited') || this.model.get('time')).format(format);
|
||||||
if (this.show_spinner) {
|
if (this.show_spinner) {
|
||||||
return tpl_spinner();
|
return tpl_spinner();
|
||||||
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
||||||
return this.renderFileProgress();
|
return this.renderFileProgress();
|
||||||
} else if (['error', 'info'].includes(this.message_type)) {
|
} else if (['error', 'info'].includes(this.model.get('type'))) {
|
||||||
return this.renderInfoMessage();
|
return this.renderInfoMessage();
|
||||||
} else {
|
} else {
|
||||||
return this.renderChatMessage();
|
return this.renderChatMessage();
|
||||||
@ -79,24 +44,35 @@ export default class Message extends CustomElement {
|
|||||||
|
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
// Listen to changes and update properties (which will trigger a
|
this.chatbox = _converse.chatboxes.get(this.jid);
|
||||||
// re-render if necessary).
|
this.model = this.chatbox.messages.get(this.mid);
|
||||||
this.listenTo(this.model, 'change', (model) => {
|
|
||||||
const chatbox = this.model.collection.chatbox;
|
this.listenTo(this.model, 'change', () => this.requestUpdate());
|
||||||
Object.assign(this, getDerivedMessageProps(chatbox, this.model));
|
this.model.vcard && this.listenTo(this.model.vcard, 'change', () => this.requestUpdate());
|
||||||
Object.keys(model.changed)
|
|
||||||
.filter(p => Object.keys(Message.properties).includes(p))
|
if (this.model.get('type') === 'groupchat') {
|
||||||
.forEach(p => (this[p] = model.changed[p]));
|
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())
|
||||||
});
|
});
|
||||||
const vcard = this.model.vcard;
|
}
|
||||||
vcard && this.listenTo(vcard, 'change', () => this.requestUpdate());
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getProps () {
|
||||||
|
return Object.assign(
|
||||||
|
this.model.toJSON(),
|
||||||
|
this.getDerivedMessageProps()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInfoMessage () {
|
renderInfoMessage () {
|
||||||
const isodate = dayjs(this.model.get('time')).toISOString();
|
const isodate = dayjs(this.model.get('time')).toISOString();
|
||||||
const i18n_retry = __('Retry');
|
const i18n_retry = __('Retry');
|
||||||
return html`
|
return html`
|
||||||
<div class="message chat-info chat-${this.message_type}"
|
<div class="message chat-info chat-${this.model.get('type')}"
|
||||||
data-isodate="${isodate}"
|
data-isodate="${isodate}"
|
||||||
data-type="${this.data_name}"
|
data-type="${this.data_name}"
|
||||||
data-value="${this.data_value}">
|
data-value="${this.data_value}">
|
||||||
@ -104,11 +80,10 @@ export default class Message extends CustomElement {
|
|||||||
<div class="chat-info__message">
|
<div class="chat-info__message">
|
||||||
${ this.model.getMessageText() }
|
${ this.model.getMessageText() }
|
||||||
</div>
|
</div>
|
||||||
${ this.reason ? html`<q class="reason">${this.reason}</q>` : `` }
|
${ this.model.get('reason') ? html`<q class="reason">${this.model.get('reason')}</q>` : `` }
|
||||||
${ this.error_text ? html`<q class="reason">${this.error_text}</q>` : `` }
|
${ this.model.get('error_text') ? html`<q class="reason">${this.model.get('error_text')}</q>` : `` }
|
||||||
${ this.retry_event_id ? html`<a class="retry" @click=${this.onRetryClicked}>${i18n_retry}</a>` : '' }
|
${ this.model.get('retry_event_id') ? html`<a class="retry" @click=${this.onRetryClicked}>${i18n_retry}</a>` : '' }
|
||||||
</div>
|
</div>`;
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFileProgress () {
|
renderFileProgress () {
|
||||||
@ -120,17 +95,17 @@ export default class Message extends CustomElement {
|
|||||||
${ renderAvatar(this.getAvatarData()) }
|
${ renderAvatar(this.getAvatarData()) }
|
||||||
<div class="chat-msg__content">
|
<div class="chat-msg__content">
|
||||||
<span class="chat-msg__text">${i18n_uploading} <strong>${filename}</strong>, ${size}</span>
|
<span class="chat-msg__text">${i18n_uploading} <strong>${filename}</strong>, ${size}</span>
|
||||||
<progress value="${this.progress}"/>
|
<progress value="${this.model.get('progress')}"/>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderChatMessage () {
|
renderChatMessage () {
|
||||||
return tpl_message(this);
|
return tpl_message(this, this.getProps());
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowAvatar () {
|
shouldShowAvatar () {
|
||||||
return api.settings.get('show_message_avatar') && !this.is_me_message && this.type !== 'headline';
|
return api.settings.get('show_message_avatar') && !this.model.isMeCommand() && this.type !== 'headline';
|
||||||
}
|
}
|
||||||
|
|
||||||
getAvatarData () {
|
getAvatarData () {
|
||||||
@ -156,7 +131,8 @@ export default class Message extends CustomElement {
|
|||||||
|
|
||||||
async onRetryClicked () {
|
async onRetryClicked () {
|
||||||
this.show_spinner = true;
|
this.show_spinner = true;
|
||||||
await api.trigger(this.retry_event_id, {'synchronous': true});
|
this.requestUpdate();
|
||||||
|
await api.trigger(this.model.get('retry_event_id'), {'synchronous': true});
|
||||||
this.model.destroy();
|
this.model.destroy();
|
||||||
this.parentElement.removeChild(this);
|
this.parentElement.removeChild(this);
|
||||||
}
|
}
|
||||||
@ -168,40 +144,69 @@ export default class Message extends CustomElement {
|
|||||||
if (prev_model === null) {
|
if (prev_model === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const date = dayjs(this.time);
|
const date = dayjs(this.model.get('time'));
|
||||||
return this.from === prev_model.get('from') &&
|
return this.model.get('from') === prev_model.get('from') &&
|
||||||
!this.is_me_message &&
|
!this.model.isMeCommand() &&
|
||||||
!prev_model.isMeCommand() &&
|
!prev_model.isMeCommand() &&
|
||||||
this.message_type !== 'info' &&
|
this.model.get('type') !== 'info' &&
|
||||||
prev_model.get('type') !== 'info' &&
|
prev_model.get('type') !== 'info' &&
|
||||||
date.isBefore(dayjs(prev_model.get('time')).add(10, 'minutes')) &&
|
date.isBefore(dayjs(prev_model.get('time')).add(10, 'minutes')) &&
|
||||||
!!this.is_encrypted === !!prev_model.get('is_encrypted');
|
!!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');
|
||||||
}
|
}
|
||||||
|
|
||||||
getExtraMessageClasses () {
|
getExtraMessageClasses () {
|
||||||
const extra_classes = [
|
const extra_classes = [
|
||||||
this.isFollowup() ? 'chat-msg--followup' : null,
|
this.isFollowup() ? 'chat-msg--followup' : null,
|
||||||
this.is_delayed ? 'delayed' : null,
|
this.model.get('is_delayed') ? 'delayed' : null,
|
||||||
this.is_me_message ? 'chat-msg--action' : null,
|
this.model.isMeCommand() ? 'chat-msg--action' : null,
|
||||||
this.is_retracted ? 'chat-msg--retracted' : null,
|
this.isRetracted() ? 'chat-msg--retracted' : null,
|
||||||
this.message_type,
|
this.model.get('type'),
|
||||||
this.shouldShowAvatar() ? 'chat-msg--with-avatar' : null,
|
this.shouldShowAvatar() ? 'chat-msg--with-avatar' : null,
|
||||||
].map(c => c);
|
].map(c => c);
|
||||||
|
|
||||||
if (this.message_type === 'groupchat') {
|
if (this.model.get('type') === 'groupchat') {
|
||||||
this.occupant_role && extra_classes.push(this.occupant_role);
|
extra_classes.push(this.getOccupantRole() ?? '');
|
||||||
this.occupant_affiliation && extra_classes.push(this.occupant_affiliation);
|
extra_classes.push(this.getOccupantAffiliation() ?? '');
|
||||||
if (this.sender === 'them' && this.has_mentions) {
|
if (this.model.get('sender') === 'them' && this.hasMentions()) {
|
||||||
extra_classes.push('mentioned');
|
extra_classes.push('mentioned');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.correcting && extra_classes.push('correcting');
|
this.model.get('correcting') && extra_classes.push('correcting');
|
||||||
return extra_classes.filter(c => c).join(" ");
|
return extra_classes.filter(c => c).join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDerivedMessageProps () {
|
||||||
|
return {
|
||||||
|
'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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getRetractionText () {
|
getRetractionText () {
|
||||||
if (this.message_type === 'groupchat' && this.moderated_by) {
|
if (this.model.get('type') === 'groupchat' && this.model.get('moderated_by')) {
|
||||||
const retracted_by_mod = this.moderated_by;
|
const retracted_by_mod = this.model.get('moderated_by');
|
||||||
const chatbox = this.model.collection.chatbox;
|
const chatbox = this.model.collection.chatbox;
|
||||||
if (!this.model.mod) {
|
if (!this.model.mod) {
|
||||||
this.model.mod =
|
this.model.mod =
|
||||||
@ -216,60 +221,62 @@ export default class Message extends CustomElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderRetraction () {
|
renderRetraction () {
|
||||||
const retraction_text = this.is_retracted ? this.getRetractionText() : null;
|
const retraction_text = this.isRetracted() ? this.getRetractionText() : null;
|
||||||
return html`
|
return html`
|
||||||
<div>${retraction_text}</div>
|
<div>${retraction_text}</div>
|
||||||
${ this.moderation_reason ? html`<q class="chat-msg--retracted__reason">${this.moderation_reason}</q>` : '' }
|
${ this.model.get('moderation_reason') ?
|
||||||
|
html`<q class="chat-msg--retracted__reason">${this.model.get('moderation_reason')}</q>` : '' }
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMessageText () {
|
renderMessageText () {
|
||||||
const i18n_edited = __('This message has been edited');
|
const i18n_edited = __('This message has been edited');
|
||||||
const i18n_show = __('Show more');
|
const i18n_show = __('Show more');
|
||||||
const is_groupchat_message = (this.message_type === 'groupchat');
|
const is_groupchat_message = (this.model.get('type') === 'groupchat');
|
||||||
const i18n_show_less = __('Show less');
|
const i18n_show_less = __('Show less');
|
||||||
|
|
||||||
const tpl_spoiler_hint = html`
|
const tpl_spoiler_hint = html`
|
||||||
<div class="chat-msg__spoiler-hint">
|
<div class="chat-msg__spoiler-hint">
|
||||||
<span class="spoiler-hint">${this.spoiler_hint}</span>
|
<span class="spoiler-hint">${this.model.get('spoiler_hint')}</span>
|
||||||
<a class="badge badge-info spoiler-toggle" href="#" @click=${this.toggleSpoilerMessage}>
|
<a class="badge badge-info spoiler-toggle" href="#" @click=${this.toggleSpoilerMessage}>
|
||||||
<i class="fa ${this.is_spoiler_visible ? 'fa-eye-slash' : 'fa-eye'}"></i>
|
<i class="fa ${this.model.get('is_spoiler_visible') ? 'fa-eye-slash' : 'fa-eye'}"></i>
|
||||||
${ this.is_spoiler_visible ? i18n_show_less : i18n_show }
|
${ this.model.get('is_spoiler_visible') ? i18n_show_less : i18n_show }
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
const spoiler_classes = this.is_spoiler ? `spoiler ${this.is_spoiler_visible ? '' : 'hidden'}` : '';
|
const spoiler_classes = this.model.get('is_spoiler') ? `spoiler ${this.model.get('is_spoiler_visible') ? '' : 'hidden'}` : '';
|
||||||
|
const text = this.model.getMessageText();
|
||||||
return html`
|
return html`
|
||||||
${ this.is_spoiler ? tpl_spoiler_hint : '' }
|
${ this.model.get('is_spoiler') ? tpl_spoiler_hint : '' }
|
||||||
${ this.subject ? html`<div class="chat-msg__subject">${this.subject}</div>` : '' }
|
${ this.model.get('subject') ? html`<div class="chat-msg__subject">${this.model.get('subject')}</div>` : '' }
|
||||||
<span>
|
<span>
|
||||||
<converse-chat-message-body
|
<converse-chat-message-body
|
||||||
class="chat-msg__text ${this.is_only_emojis ? 'chat-msg__text--larger' : ''} ${spoiler_classes}"
|
class="chat-msg__text ${this.model.get('is_only_emojis') ? 'chat-msg__text--larger' : ''} ${spoiler_classes}"
|
||||||
.model="${this.model}"
|
.model="${this.model}"
|
||||||
?is_me_message="${this.is_me_message}"
|
?is_me_message="${this.model.isMeCommand()}"
|
||||||
?is_only_emojis="${this.is_only_emojis}"
|
?is_only_emojis="${this.model.get('is_only_emojis')}"
|
||||||
?is_spoiler="${this.is_spoiler}"
|
?is_spoiler="${this.model.get('is_spoiler')}"
|
||||||
?is_spoiler_visible="${this.is_spoiler_visible}"
|
?is_spoiler_visible="${this.model.get('is_spoiler_visible')}"
|
||||||
text="${this.model.getMessageText()}"></converse-chat-message-body>
|
text="${text}"></converse-chat-message-body>
|
||||||
${ (this.received && !this.is_me_message && !is_groupchat_message) ? html`<span class="fa fa-check chat-msg__receipt"></span>` : '' }
|
${ (this.model.get('received') && !this.model.isMeCommand() && !is_groupchat_message) ? html`<span class="fa fa-check chat-msg__receipt"></span>` : '' }
|
||||||
${ (this.edited) ? html`<i title="${ i18n_edited }" class="fa fa-edit chat-msg__edit-modal" @click=${this.showMessageVersionsModal}></i>` : '' }
|
${ (this.model.get('edited')) ? html`<i title="${ i18n_edited }" class="fa fa-edit chat-msg__edit-modal" @click=${this.showMessageVersionsModal}></i>` : '' }
|
||||||
</span>
|
</span>
|
||||||
${ this.oob_url ? html`<div class="chat-msg__media">${u.getOOBURLMarkup(_converse, this.oob_url)}</div>` : '' }
|
${ 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.error_text || this.error }</div>
|
<div class="chat-msg__error">${ this.model.get('error_text') || this.model.get('error') }</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAvatarByline () {
|
renderAvatarByline () {
|
||||||
return html`
|
return html`
|
||||||
${ this.hats.map(h => html`<span class="badge badge-secondary">${h.title}</span>`) }
|
${ _converse.getHats(this.model).map(h => html`<span class="badge badge-secondary">${h.title}</span>`) }
|
||||||
<time timestamp="${this.edited || this.time}" class="chat-msg__time">${this.pretty_time}</time>
|
<time timestamp="${this.model.get('edited') || this.model.get('time')}" class="chat-msg__time">${this.pretty_time}</time>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
showUserModal (ev) {
|
showUserModal (ev) {
|
||||||
if (this.model.get('sender') === 'me') {
|
if (this.model.get('sender') === 'me') {
|
||||||
_converse.xmppstatusview.showProfileModal(ev);
|
_converse.xmppstatusview.showProfileModal(ev);
|
||||||
} else if (this.message_type === 'groupchat') {
|
} else if (this.model.get('type') === 'groupchat') {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
api.modal.show(OccupantModal, { 'model': this.model.occupant }, ev);
|
api.modal.show(OccupantModal, { 'model': this.model.occupant }, ev);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,11 +4,11 @@ import { html } from "lit-html";
|
|||||||
import { renderAvatar } from 'shared/directives/avatar';
|
import { renderAvatar } from 'shared/directives/avatar';
|
||||||
|
|
||||||
|
|
||||||
export default (o) => {
|
export default (el, o) => {
|
||||||
const i18n_new_messages = __('New messages');
|
const i18n_new_messages = __('New messages');
|
||||||
return html`
|
return html`
|
||||||
${ o.is_first_unread ? html`<div class="message separator"><hr class="separator"><span class="separator-text">${ i18n_new_messages }</span></div>` : '' }
|
${ o.is_first_unread ? html`<div class="message separator"><hr class="separator"><span class="separator-text">${ i18n_new_messages }</span></div>` : '' }
|
||||||
<div class="message chat-msg ${ o.getExtraMessageClasses() }"
|
<div class="message chat-msg ${ el.getExtraMessageClasses() }"
|
||||||
data-isodate="${o.time}"
|
data-isodate="${o.time}"
|
||||||
data-msgid="${o.msgid}"
|
data-msgid="${o.msgid}"
|
||||||
data-from="${o.from}"
|
data-from="${o.from}"
|
||||||
@ -17,13 +17,13 @@ export default (o) => {
|
|||||||
<!-- Anchor to allow us to scroll the message into view -->
|
<!-- Anchor to allow us to scroll the message into view -->
|
||||||
<a id="${o.msgid}"></a>
|
<a id="${o.msgid}"></a>
|
||||||
|
|
||||||
<a class="show-msg-author-modal" @click=${o.showUserModal}>${ o.shouldShowAvatar() ? renderAvatar(o.getAvatarData()) : '' }</a>
|
<a class="show-msg-author-modal" @click=${el.showUserModal}>${ o.should_show_avatar ? renderAvatar(el.getAvatarData()) : '' }</a>
|
||||||
<div class="chat-msg__content chat-msg__content--${o.sender} ${o.is_me_message ? 'chat-msg__content--action' : ''}">
|
<div class="chat-msg__content chat-msg__content--${o.sender} ${o.is_me_message ? 'chat-msg__content--action' : ''}">
|
||||||
|
|
||||||
${ !o.is_me_message ? html`
|
${ !o.is_me_message ? html`
|
||||||
<span class="chat-msg__heading">
|
<span class="chat-msg__heading">
|
||||||
<span class="chat-msg__author"><a class="show-msg-author-modal" @click=${o.showUserModal}>${o.username}</a></span>
|
<span class="chat-msg__author"><a class="show-msg-author-modal" @click=${el.showUserModal}>${o.username}</a></span>
|
||||||
${ o.renderAvatarByline() }
|
${ el.renderAvatarByline() }
|
||||||
${ o.is_encrypted ? html`<span class="fa fa-lock"></span>` : '' }
|
${ o.is_encrypted ? html`<span class="fa fa-lock"></span>` : '' }
|
||||||
</span>` : '' }
|
</span>` : '' }
|
||||||
<div class="chat-msg__body chat-msg__body--${o.message_type} ${o.received ? 'chat-msg__body--received' : '' } ${o.is_delayed ? 'chat-msg__body--delayed' : '' }">
|
<div class="chat-msg__body chat-msg__body--${o.message_type} ${o.received ? 'chat-msg__body--received' : '' } ${o.is_delayed ? 'chat-msg__body--delayed' : '' }">
|
||||||
@ -31,23 +31,23 @@ export default (o) => {
|
|||||||
${ (o.is_me_message) ? html`
|
${ (o.is_me_message) ? html`
|
||||||
<time timestamp="${o.edited || o.time}" class="chat-msg__time">${o.pretty_time}</time>
|
<time timestamp="${o.edited || o.time}" class="chat-msg__time">${o.pretty_time}</time>
|
||||||
<span class="chat-msg__author">${ o.is_me_message ? '**' : ''}${o.username}</span> ` : '' }
|
<span class="chat-msg__author">${ o.is_me_message ? '**' : ''}${o.username}</span> ` : '' }
|
||||||
${ o.is_retracted ? o.renderRetraction() : o.renderMessageText() }
|
${ o.is_retracted ? el.renderRetraction() : el.renderMessageText() }
|
||||||
</div>
|
</div>
|
||||||
<converse-message-actions
|
<converse-message-actions
|
||||||
.model=${o.model}
|
.model=${el.model}
|
||||||
?correcting="${o.correcting}"
|
?correcting="${o.correcting}"
|
||||||
?editable="${o.editable}"
|
?editable="${o.editable}"
|
||||||
?is_retracted="${o.is_retracted}"
|
?is_retracted="${o.is_retracted}"
|
||||||
?hide_url_previews="${o.model.get('hide_url_previews')}"
|
?hide_url_previews="${el.model.get('hide_url_previews')}"
|
||||||
unfurls="${o.model.get('ogp_metadata')?.length}"
|
unfurls="${el.model.get('ogp_metadata')?.length}"
|
||||||
message_type="${o.message_type}"></converse-message-actions>
|
message_type="${o.message_type}"></converse-message-actions>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${ !o.model.get('hide_url_previews') ? o.model.get('ogp_metadata')?.map(m =>
|
${ !el.model.get('hide_url_previews') ? el.model.get('ogp_metadata')?.map(m =>
|
||||||
html`<converse-message-unfurl
|
html`<converse-message-unfurl
|
||||||
@animationend="${o.onUnfurlAnimationEnd}"
|
@animationend="${el.onUnfurlAnimationEnd}"
|
||||||
class="${o.model.get('url_preview_transition')}"
|
class="${el.model.get('url_preview_transition')}"
|
||||||
jid="${o.model.collection.chatbox?.get('jid')}"
|
jid="${el.chatbox?.get('jid')}"
|
||||||
description="${m['og:description'] || ''}"
|
description="${m['og:description'] || ''}"
|
||||||
title="${m['og:title'] || ''}"
|
title="${m['og:title'] || ''}"
|
||||||
image="${m['og:image'] || ''}"
|
image="${m['og:image'] || ''}"
|
||||||
|
Loading…
Reference in New Issue
Block a user