diff --git a/spec/muc_messages.js b/spec/muc_messages.js index 86f33a5bc..475f53bd3 100644 --- a/spec/muc_messages.js +++ b/spec/muc_messages.js @@ -652,7 +652,7 @@ from="${msg_obj.get('from')}" to="${_converse.connection.jid}" type="groupchat"> - ${msg_obj.get('message')} + ${msg_obj.get('message')} @@ -878,6 +878,17 @@ }))); }); + // Also check that nicks from received messages, (but for which + // we don't have occupant objects) can be mentioned. + const stanza = u.toStanza(` + + Boo! + `); + await view.model.onMessage(stanza); + // Run a few unit tests for the parseTextForReferences method let [text, references] = view.model.parseTextForReferences('hello z3r0') expect(references.length).toBe(0); @@ -935,6 +946,12 @@ expect(references.length).toBe(0); expect(JSON.stringify(references)) .toBe('[]'); + + [text, references] = view.model.parseTextForReferences('@gh0st where are you?') + expect(text).toBe('gh0st where are you?'); + expect(references.length).toBe(1); + expect(JSON.stringify(references)) + .toBe('[{"begin":0,"end":5,"value":"gh0st","type":"mention","uri":"xmpp:lounge@montague.lit/gh0st"}]'); done(); })); diff --git a/src/converse-muc-views.js b/src/converse-muc-views.js index 4849754d7..e3a66f02c 100644 --- a/src/converse-muc-views.js +++ b/src/converse-muc-views.js @@ -845,12 +845,7 @@ converse.plugins.add('converse-muc-views', { }, getAutoCompleteList () { - // Create an array of unique nicknames based on the occupants and messages. - const nicks = [...new Set([ - ...this.model.occupants.map(o => o.get('nick')), - ...this.model.messages.map(m => m.get('nick')) - ])].filter(n => n); - return nicks.map(nick => ({'label': nick, 'value': `@${nick}`})); + return this.model.getAllKnownNicknames().map(nick => ({'label': nick, 'value': `@${nick}`})); }, getAutoCompleteListItem(text, input) { diff --git a/src/headless/converse-muc.js b/src/headless/converse-muc.js index 437b93a69..98a3b5507 100644 --- a/src/headless/converse-muc.js +++ b/src/headless/converse-muc.js @@ -829,11 +829,22 @@ converse.plugins.add('converse-muc', { _converse.connection.sendPresence(presence); }, + /** + * Return an array of unique nicknames based on all occupants and messages in this MUC. + * @private + * @method _converse.ChatRoom#getAllKnownNicknames + * @returns { String[] } + */ + getAllKnownNicknames () { + return [...new Set([ + ...this.occupants.map(o => o.get('nick')), + ...this.messages.map(m => m.get('nick')) + ])].filter(n => n); + }, + getReferenceForMention (mention, index) { - const longest_match = u.getLongestSubstring( - mention, - this.occupants.map(o => o.getDisplayName()) - ); + const nicknames = this.getAllKnownNicknames(); + const longest_match = u.getLongestSubstring(mention, nicknames); if (!longest_match) { return null; } @@ -843,22 +854,26 @@ converse.plugins.add('converse-muc', { // match. return null; } + + let uri; const occupant = this.occupants.findOccupant({'nick': longest_match}) || - this.occupants.findOccupant({'jid': longest_match}); - if (!occupant) { - return null; + u.isValidJID(longest_match) && this.occupants.findOccupant({'jid': longest_match}); + + if (occupant) { + uri = occupant.get('jid') || `${this.get('jid')}/${occupant.get('nick')}`; + } else if (nicknames.includes(longest_match)) { + // TODO: show a warning to the user that the person is not currently in the chat + uri = `${this.get('jid')}/${longest_match}`; + } else { + return; } const obj = { 'begin': index, 'end': index + longest_match.length, 'value': longest_match, - 'type': 'mention' + 'type': 'mention', + 'uri': encodeURI(`xmpp:${uri}`) }; - if (occupant.get('jid')) { - obj.uri = encodeURI(`xmpp:${occupant.get('jid')}`); - } else { - obj.uri = encodeURI(`xmpp:${this.get('jid')}/${occupant.get('nick')}`); - } return obj; }, @@ -898,16 +913,16 @@ converse.plugins.add('converse-muc', { const origin_id = u.getUniqueId(); return { + is_spoiler, + origin_id, + references, 'id': origin_id, 'msgid': origin_id, - 'origin_id': origin_id, 'from': `${this.get('jid')}/${this.get('nick')}`, 'fullname': this.get('nick'), 'is_only_emojis': text ? u.isOnlyEmojis(text) : false, - 'is_spoiler': is_spoiler, 'message': text ? u.httpToGeoUri(u.shortnameToUnicode(text), _converse) : undefined, 'nick': this.get('nick'), - 'references': references, 'sender': 'me', 'spoiler_hint': is_spoiler ? spoiler_hint : undefined, 'type': 'groupchat' @@ -915,9 +930,9 @@ converse.plugins.add('converse-muc', { }, /** - * Utility method to construct the JID for the current user - * as occupant of the groupchat. - * + * Utility method to construct the JID for the current user as occupant of the groupchat. + * @private + * @method _converse.ChatRoom#getRoomJIDAndNick * @returns {string} - The groupchat JID with the user's nickname added at the end. * @example groupchat@conference.example.org/nickname */