converse.js
Version:
Browser based XMPP chat client
137 lines (113 loc) • 4.67 kB
JavaScript
import { Strophe } from 'strophe.js';
import _converse from '../../shared/_converse.js';
import api from '../../shared/api/index.js';
import BaseMessage from '../../shared/message.js';
class MUCMessage extends BaseMessage {
/**
* @typedef {import('./occupant').default} MUCOccupant
*/
initialize () {
super.initialize();
// If `type` changes from `error` to `groupchat`, we want to set the occupant. See #2733
this.on('change:type', () => this.setOccupant());
this.setOccupant();
/**
* Triggered once a { @link MUCMessage} has been created and initialized.
* @event _converse#chatRoomMessageInitialized
* @type {MUCMessage}
* @example _converse.api.listen.on('chatRoomMessageInitialized', model => { ... });
*/
api.trigger('chatRoomMessageInitialized', this);
}
get occupants () {
return (this.get('type') === 'chat') ? this.chatbox.collection : this.chatbox.occupants;
}
getDisplayName () {
return this.occupant?.getDisplayName() || this.get('nick');
}
/**
* Determines whether this messsage may be moderated,
* based on configuration settings and server support.
* @method _converse.ChatRoomMessages#mayBeModerated
* @returns {Promise<boolean>}
*/
async mayBeModerated () {
if (typeof this.get('from_muc') === 'undefined') {
// If from_muc is not defined, then this message hasn't been
// reflected yet, which means we won't have a XEP-0359 stanza id.
return;
}
return (
['all', 'moderator'].includes(api.settings.get('allow_message_retraction')) &&
this.get(`stanza_id ${this.get('from_muc')}`) && await this.chatbox.canModerateMessages()
);
}
checkValidity () {
const result = super.checkValidity();
!result && this.chatbox.debouncedRejoin();
return result;
}
onOccupantRemoved () {
this.stopListening(this.occupant);
delete this.occupant;
this.listenTo(this.occupants, 'add', this.onOccupantAdded);
}
/**
* @param {MUCOccupant} [occupant]
*/
onOccupantAdded (occupant) {
if (this.get('occupant_id')) {
if (occupant.get('occupant_id') !== this.get('occupant_id')) {
return;
}
} else if (occupant.get('nick') !== Strophe.getResourceFromJid(this.get('from'))) {
return;
}
this.setOccupant(occupant)
}
getOccupant() {
return this.occupant || this.setOccupant();
}
/**
* @param {MUCOccupant} [occupant]
* @return {MUCOccupant}
*/
setOccupant (occupant) {
if (!['groupchat', 'chat'].includes(this.get('type')) || this.isEphemeral()) {
return;
}
if (occupant) {
this.occupant = occupant;
} else if (this.get('type') === 'chat' && this.get('sender') === 'them') {
this.occupant = this.chatbox;
} else {
if (this.occupant) return;
const nick = Strophe.getResourceFromJid(this.get('from'));
const occupant_id = this.get('occupant_id');
this.occupant = nick || occupant_id ? this.occupants.findOccupant({ nick, occupant_id }) : null;
if (!this.occupant) {
const jid = this.get('from_real_jid');
if (!nick && !occupant_id && !jid) {
// Tombstones of retracted messages might have no occupant info
return;
}
this.occupant = this.occupants.create({ nick, occupant_id, jid });
if (api.settings.get('muc_send_probes')) {
const jid = `${this.chatbox.get('jid')}/${nick}`;
api.user.presence.send({ to: jid, type: 'probe' });
}
}
}
if (this.get('from_real_jid') !== this.occupant.get('jid')) {
this.save('from_real_jid', this.occupant.get('jid'));
}
this.trigger('occupant:add');
this.listenTo(this.occupant, 'change', (changed) => this.trigger('occupant:change', changed));
this.listenTo(this.occupant, 'vcard:add', (changed) => this.trigger('occupant:change', changed));
this.listenTo(this.occupant, 'vcard:change', (changed) => this.trigger('occupant:change', changed));
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
this.stopListening(this.occupants, 'add', this.onOccupantAdded);
return this.occupant;
}
}
export default MUCMessage;