Add method to determine references from message text
This commit is contained in:
parent
e10d9b074e
commit
f2b017ec89
@ -13,7 +13,7 @@
|
|||||||
const Strophe = converse.env.Strophe;
|
const Strophe = converse.env.Strophe;
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
|
|
||||||
return describe("A groupchat textarea", function () {
|
describe("The nickname autocomplete feature", function () {
|
||||||
|
|
||||||
it("shows all autocompletion options when the user presses @",
|
it("shows all autocompletion options when the user presses @",
|
||||||
mock.initConverseWithPromises(
|
mock.initConverseWithPromises(
|
||||||
@ -146,7 +146,7 @@
|
|||||||
'stopPropagation': _.noop,
|
'stopPropagation': _.noop,
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
});
|
});
|
||||||
expect(textarea.value).toBe('hello s some2 ');
|
expect(textarea.value).toBe('hello s @some2 ');
|
||||||
|
|
||||||
// Test that pressing tab twice selects
|
// Test that pressing tab twice selects
|
||||||
presence = $pres({
|
presence = $pres({
|
||||||
@ -166,7 +166,7 @@
|
|||||||
|
|
||||||
view.keyPressed(tab_event);
|
view.keyPressed(tab_event);
|
||||||
view.keyUp(tab_event);
|
view.keyUp(tab_event);
|
||||||
expect(textarea.value).toBe('hello z3r0 ');
|
expect(textarea.value).toBe('hello @z3r0 ');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}).catch(_.partial(console.error, _));
|
}).catch(_.partial(console.error, _));
|
||||||
|
@ -1202,6 +1202,60 @@
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
describe("in which someone is mentioned", function () {
|
||||||
|
|
||||||
|
it("includes XEP-0372 references to that person",
|
||||||
|
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'
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
|
let [text, references] = view.model.parseForReferences('hello z3r0')
|
||||||
|
expect(references.length).toBe(0);
|
||||||
|
expect(text).toBe('hello z3r0');
|
||||||
|
|
||||||
|
[text, references] = view.model.parseForReferences('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?')
|
||||||
|
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')
|
||||||
|
expect(text).toBe('yo @gib');
|
||||||
|
expect(references.length).toBe(0);
|
||||||
|
|
||||||
|
[text, references] = view.model.parseForReferences('yo @gibsonian')
|
||||||
|
expect(text).toBe('yo @gibsonian');
|
||||||
|
expect(references.length).toBe(0);
|
||||||
|
done();
|
||||||
|
}).catch(_.partial(console.error, _));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("when received from someone else", function () {
|
describe("when received from someone else", function () {
|
||||||
|
|
||||||
it("will open a chatbox and be displayed inside it",
|
it("will open a chatbox and be displayed inside it",
|
||||||
|
@ -237,7 +237,6 @@
|
|||||||
} else {
|
} else {
|
||||||
selected = this.ul.children[this.index];
|
selected = this.ul.children[this.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
const suggestion = this.suggestions[this.index];
|
const suggestion = this.suggestions[this.index];
|
||||||
this.insertValue(suggestion);
|
this.insertValue(suggestion);
|
||||||
|
@ -617,7 +617,7 @@
|
|||||||
'min_chars': 1,
|
'min_chars': 1,
|
||||||
'match_current_word': true,
|
'match_current_word': true,
|
||||||
'match_on_tab': true,
|
'match_on_tab': true,
|
||||||
'list': () => this.model.occupants.map(o => ({'label': o.get('nick'), 'value': o.get('nick')})),
|
'list': () => this.model.occupants.map(o => ({'label': o.get('nick'), 'value': `@${o.get('nick')}`})),
|
||||||
'filter': _converse.FILTER_STARTSWITH,
|
'filter': _converse.FILTER_STARTSWITH,
|
||||||
'trigger_on_at': true
|
'trigger_on_at': true
|
||||||
});
|
});
|
||||||
|
@ -308,14 +308,75 @@
|
|||||||
_converse.connection.sendPresence(presence);
|
_converse.connection.sendPresence(presence);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getReferenceForMention (mention, index) {
|
||||||
|
const longest_match = u.getLongestSubstring(mention, this.occupants.map(o => o.get('nick')));
|
||||||
|
if (!longest_match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ((mention[longest_match.length] || '').match(/[A-Za-zäëïöüâêîôûáéíóúàèìòùÄËÏÖÜÂÊÎÔÛÁÉÍÓÚÀÈÌÒÙ]/i)) {
|
||||||
|
// avoid false positives, i.e. mentions that have
|
||||||
|
// further alphabetical characters than our longest
|
||||||
|
// match.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const occupant = this.occupants.findOccupant({'nick': longest_match});
|
||||||
|
if (!occupant) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const obj = {
|
||||||
|
'begin': index,
|
||||||
|
'end': index + longest_match.length,
|
||||||
|
'type': 'mention'
|
||||||
|
};
|
||||||
|
if (occupant.get('jid')) {
|
||||||
|
obj.uri = `xmpp:${occupant.get('jid')}`
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
extractReference (text, index) {
|
||||||
|
for (let i=index; i<text.length; i++) {
|
||||||
|
if (text[i] !== '@') {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
const match = text.slice(i+1),
|
||||||
|
ref = this.getReferenceForMention(match, i)
|
||||||
|
if (ref) {
|
||||||
|
return [text.slice(0, i) + match, ref, i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
parseForReferences (text) {
|
||||||
|
const refs = [];
|
||||||
|
let index = 0;
|
||||||
|
while (index < (text || '').length) {
|
||||||
|
const result = this.extractReference(text, index);
|
||||||
|
if (result) {
|
||||||
|
text = result[0]; // @ gets filtered out
|
||||||
|
refs.push(result[1]);
|
||||||
|
index = result[2];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [text, refs];
|
||||||
|
},
|
||||||
|
|
||||||
getOutgoingMessageAttributes (text, spoiler_hint) {
|
getOutgoingMessageAttributes (text, spoiler_hint) {
|
||||||
const is_spoiler = this.get('composing_spoiler');
|
const is_spoiler = this.get('composing_spoiler');
|
||||||
|
var references;
|
||||||
|
[text, references] = this.parseForReferences(text);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'nick': this.get('nick'),
|
|
||||||
'from': `${this.get('jid')}/${this.get('nick')}`,
|
'from': `${this.get('jid')}/${this.get('nick')}`,
|
||||||
'fullname': this.get('nick'),
|
'fullname': this.get('nick'),
|
||||||
'is_spoiler': is_spoiler,
|
'is_spoiler': is_spoiler,
|
||||||
'message': text ? u.httpToGeoUri(emojione.shortnameToUnicode(text), _converse) : undefined,
|
'message': text ? u.httpToGeoUri(emojione.shortnameToUnicode(text), _converse) : undefined,
|
||||||
|
'nick': this.get('nick'),
|
||||||
|
'references': references,
|
||||||
'sender': 'me',
|
'sender': 'me',
|
||||||
'spoiler_hint': is_spoiler ? spoiler_hint : undefined,
|
'spoiler_hint': is_spoiler ? spoiler_hint : undefined,
|
||||||
'type': 'groupchat'
|
'type': 'groupchat'
|
||||||
|
@ -98,6 +98,21 @@
|
|||||||
|
|
||||||
var u = {};
|
var u = {};
|
||||||
|
|
||||||
|
u.getLongestSubstring = function (string, candidates) {
|
||||||
|
function reducer (accumulator, current_value) {
|
||||||
|
if (string.startsWith(current_value)) {
|
||||||
|
if (current_value.length > accumulator.length) {
|
||||||
|
return current_value;
|
||||||
|
} else {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidates.reduce(reducer, '');
|
||||||
|
}
|
||||||
|
|
||||||
u.getNextElement = function (el, selector='*') {
|
u.getNextElement = function (el, selector='*') {
|
||||||
let next_el = el.nextElementSibling;
|
let next_el = el.nextElementSibling;
|
||||||
while (!_.isNull(next_el) && !sizzle.matchesSelector(next_el, selector)) {
|
while (!_.isNull(next_el) && !sizzle.matchesSelector(next_el, selector)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user