Render mentions in a message
This commit is contained in:
parent
15df9b8605
commit
b7eb19e225
@ -21,8 +21,9 @@
|
||||
- Add a checkbox to indicate whether a trusted device is being used or not.
|
||||
If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout.
|
||||
If the device is trusted, localStorage is used and user data is cached indefinitely.
|
||||
- Initial support for XEP-0357 Push Notifications, specifically registering an "App Server".
|
||||
- Initial support for [XEP-0357 Push Notifications](https://xmpp.org/extensions/xep-0357.html), specifically registering an "App Server".
|
||||
- Add support for logging in via OAuth (see the [oauth_providers](https://conversejs.org/docs/html/configurations.html#oauth-providers) setting)
|
||||
- Add support for [XEP-0372 References](https://xmpp.org/extensions/xep-0372.html), specifically section "3.2 Mentions".
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
@ -8540,9 +8540,6 @@ body.reset {
|
||||
#conversejs.converse-embedded .chatroom .box-flyout .chatroom-body .chat-info.badge,
|
||||
#conversejs .chatroom .box-flyout .chatroom-body .chat-info.badge {
|
||||
color: white; }
|
||||
#conversejs.converse-embedded .chatroom .box-flyout .chatroom-body .mentioned,
|
||||
#conversejs .chatroom .box-flyout .chatroom-body .mentioned {
|
||||
font-weight: bold; }
|
||||
#conversejs.converse-embedded .chatroom .box-flyout .chatroom-body .disconnect-container,
|
||||
#conversejs .chatroom .box-flyout .chatroom-body .disconnect-container {
|
||||
margin: 1em;
|
||||
@ -8799,6 +8796,10 @@ body.reset {
|
||||
border: 1.2em solid #E7A151;
|
||||
border-top: 0.8em solid #E7A151; }
|
||||
|
||||
#conversejs .message .mention {
|
||||
font-weight: bold; }
|
||||
#conversejs .message .mention--self {
|
||||
font-weight: normal; }
|
||||
#conversejs .message.date-separator {
|
||||
height: 2em;
|
||||
margin: 0;
|
||||
|
@ -116,9 +116,6 @@
|
||||
color: $chat-head-text-color;
|
||||
}
|
||||
}
|
||||
.mentioned {
|
||||
font-weight: bold;
|
||||
}
|
||||
.disconnect-container {
|
||||
margin: 1em;
|
||||
width: 100%;
|
||||
|
@ -1,6 +1,12 @@
|
||||
#conversejs {
|
||||
.message {
|
||||
|
||||
.mention {
|
||||
font-weight: bold;
|
||||
}
|
||||
.mention--self {
|
||||
font-weight: normal;
|
||||
}
|
||||
&.date-separator {
|
||||
height: 2em;
|
||||
margin: 0;
|
||||
|
@ -2089,6 +2089,52 @@
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
describe("when received", function () {
|
||||
|
||||
it("highlights all users mentioned via XEP-0372 references",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'tom')
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
|
||||
_converse.connection._dataRecv(test_utils.createRequest(
|
||||
$pres({
|
||||
'to': 'tom@localhost/resource',
|
||||
'from': `lounge@localhost/${nick}`
|
||||
})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': `${nick}@localhost/resource`,
|
||||
'role': 'participant'
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
const msg = $msg({
|
||||
from: 'lounge@localhost/gibson',
|
||||
id: (new Date()).getTime(),
|
||||
to: 'dummy@localhost',
|
||||
type: 'groupchat'
|
||||
}).c('body').t('hello z3r0 tom mr.robot, how are you?').up()
|
||||
.c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'6', 'end':'10', 'type':'mention', 'uri':'xmpp:z3r0@localhost'}).up()
|
||||
.c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'11', 'end':'14', 'type':'mention', 'uri':'xmpp:dummy@localhost'}).up()
|
||||
.c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'15', 'end':'23', 'type':'mention', 'uri':'xmpp:mr.robot@localhost'}).nodeTree;
|
||||
view.model.onMessage(msg);
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg__text').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__text').outerHTML).toBe(
|
||||
'<div class="chat-msg__text">hello <span class="mention">z3r0</span> '+
|
||||
'<span class="mention mention--self badge badge-info">tom</span> '+
|
||||
'<span class="mention">mr.robot</span>, how are you?</div>');
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
});
|
||||
|
||||
describe("in which someone is mentioned", function () {
|
||||
|
||||
it("gets parsed for mentions which get turned into references",
|
||||
@ -2113,33 +2159,33 @@
|
||||
})));
|
||||
});
|
||||
|
||||
// Run a few unit tests for the parseForReferences method
|
||||
let [text, references] = view.model.parseForReferences('hello z3r0')
|
||||
// Run a few unit tests for the parseTextForReferences method
|
||||
let [text, references] = view.model.parseTextForReferences('hello z3r0')
|
||||
expect(references.length).toBe(0);
|
||||
expect(text).toBe('hello z3r0');
|
||||
|
||||
[text, references] = view.model.parseForReferences('hello @z3r0')
|
||||
[text, references] = view.model.parseTextForReferences('hello @z3r0')
|
||||
expect(references.length).toBe(1);
|
||||
expect(text).toBe('hello z3r0');
|
||||
expect(JSON.stringify(references))
|
||||
.toBe('[{"begin":6,"end":10,"type":"mention","uri":"xmpp:z3r0@localhost"}]');
|
||||
|
||||
[text, references] = view.model.parseForReferences('hello @some1 @z3r0 @gibson @mr.robot, how are you?')
|
||||
[text, references] = view.model.parseTextForReferences('hello @some1 @z3r0 @gibson @mr.robot, how are you?')
|
||||
expect(text).toBe('hello @some1 z3r0 gibson mr.robot, how are you?');
|
||||
expect(JSON.stringify(references))
|
||||
.toBe('[{"begin":13,"end":17,"type":"mention","uri":"xmpp:z3r0@localhost"},'+
|
||||
'{"begin":18,"end":24,"type":"mention","uri":"xmpp:gibson@localhost"},'+
|
||||
'{"begin":25,"end":33,"type":"mention","uri":"xmpp:mr.robot@localhost"}]');
|
||||
|
||||
[text, references] = view.model.parseForReferences('yo @gib')
|
||||
[text, references] = view.model.parseTextForReferences('yo @gib')
|
||||
expect(text).toBe('yo @gib');
|
||||
expect(references.length).toBe(0);
|
||||
|
||||
[text, references] = view.model.parseForReferences('yo @gibsonian')
|
||||
[text, references] = view.model.parseTextForReferences('yo @gibsonian')
|
||||
expect(text).toBe('yo @gibsonian');
|
||||
expect(references.length).toBe(0);
|
||||
|
||||
[text, references] = view.model.parseForReferences('@gibson')
|
||||
[text, references] = view.model.parseTextForReferences('@gibson')
|
||||
expect(text).toBe('gibson');
|
||||
expect(references.length).toBe(1);
|
||||
expect(JSON.stringify(references))
|
||||
@ -2190,9 +2236,9 @@
|
||||
`xmlns='jabber:client'>`+
|
||||
`<body>hello z3r0 gibson mr.robot, how are you?</body>`+
|
||||
`<active xmlns='http://jabber.org/protocol/chatstates'/>`+
|
||||
`<reference xmlns='urn:xmpp:reference:0' begin='6' end='10' type='mention' uri='xmpp:z3r0@localhost'/>`+
|
||||
`<reference xmlns='urn:xmpp:reference:0' begin='11' end='17' type='mention' uri='xmpp:gibson@localhost'/>`+
|
||||
`<reference xmlns='urn:xmpp:reference:0' begin='18' end='26' type='mention' uri='xmpp:mr.robot@localhost'/>`+
|
||||
`<reference xmlns='urn:xmpp:reference:0' begin='11' end='17' type='mention' uri='xmpp:gibson@localhost'/>`+
|
||||
`<reference xmlns='urn:xmpp:reference:0' begin='6' end='10' type='mention' uri='xmpp:z3r0@localhost'/>`+
|
||||
`</message>`);
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
|
@ -299,6 +299,7 @@
|
||||
older_versions.push(message.get('message'));
|
||||
message.save({
|
||||
'message': _converse.chatboxes.getMessageBody(stanza),
|
||||
'references': this.getReferencesFromStanza(stanza),
|
||||
'older_versions': older_versions,
|
||||
'edited': true
|
||||
});
|
||||
@ -459,6 +460,17 @@
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
},
|
||||
|
||||
getReferencesFromStanza (stanza) {
|
||||
return sizzle(`reference[xmlns="${Strophe.NS.REFERENCE}"]`, stanza).map(ref => {
|
||||
return {
|
||||
'begin': ref.getAttribute('begin'),
|
||||
'end': ref.getAttribute('end'),
|
||||
'type': ref.getAttribute('type'),
|
||||
'uri': ref.getAttribute('uri')
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getMessageAttributesFromStanza (stanza, original_stanza) {
|
||||
/* Parses a passed in message stanza and returns an object
|
||||
* of attributes.
|
||||
@ -488,6 +500,7 @@
|
||||
'is_delayed': !_.isNil(delay),
|
||||
'is_spoiler': !_.isNil(spoiler),
|
||||
'message': _converse.chatboxes.getMessageBody(stanza) || undefined,
|
||||
'references': this.getReferencesFromStanza(stanza),
|
||||
'msgid': stanza.getAttribute('id'),
|
||||
'time': delay ? delay.getAttribute('stamp') : moment().format(),
|
||||
'type': stanza.getAttribute('type')
|
||||
|
@ -167,6 +167,7 @@
|
||||
text = xss.filterXSS(text, {'whiteList': {}});
|
||||
msg_content.innerHTML = _.flow(
|
||||
_.partial(u.geoUriToHttp, _, _converse.geouri_replacement),
|
||||
_.partial(u.addMentions, _, this.model.get('references'), this.model.collection.chatbox),
|
||||
u.addHyperlinks,
|
||||
u.renderNewLines,
|
||||
_.partial(u.addEmoji, _converse, emojione, _)
|
||||
|
@ -349,7 +349,7 @@
|
||||
return;
|
||||
},
|
||||
|
||||
parseForReferences (text) {
|
||||
parseTextForReferences (text) {
|
||||
const refs = [];
|
||||
let index = 0;
|
||||
while (index < (text || '').length) {
|
||||
@ -368,7 +368,7 @@
|
||||
getOutgoingMessageAttributes (text, spoiler_hint) {
|
||||
const is_spoiler = this.get('composing_spoiler');
|
||||
var references;
|
||||
[text, references] = this.parseForReferences(text);
|
||||
[text, references] = this.parseTextForReferences(text);
|
||||
|
||||
return {
|
||||
'from': `${this.get('jid')}/${this.get('nick')}`,
|
||||
|
@ -229,6 +229,25 @@
|
||||
return encodeURI(decodeURI(url)).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
|
||||
};
|
||||
|
||||
u.addMentions = function (text, references, chatbox) {
|
||||
if (chatbox.get('message_type') !== 'groupchat') {
|
||||
return text;
|
||||
}
|
||||
const nick = chatbox.get('nick');
|
||||
references
|
||||
.sort((a, b) => b.begin - a.begin)
|
||||
.forEach(ref => {
|
||||
const mention = text.slice(ref.begin, ref.end)
|
||||
chatbox;
|
||||
if (mention === nick) {
|
||||
text = text.slice(0, ref.begin) + `<span class="mention mention--self badge badge-info">${mention}</span>` + text.slice(ref.end);
|
||||
} else {
|
||||
text = text.slice(0, ref.begin) + `<span class="mention">${mention}</span>` + text.slice(ref.end);
|
||||
}
|
||||
});
|
||||
return text;
|
||||
};
|
||||
|
||||
u.addHyperlinks = function (text) {
|
||||
return URI.withinString(text, function (url) {
|
||||
var uri = new URI(url);
|
||||
|
Loading…
Reference in New Issue
Block a user