Skip to content

Commit efd4e50

Browse files
authored
Fix #2231 add sort by query (#2234)
Use of lowercase letters and Infinity to avoid calculation errors when the index is -1
1 parent e761923 commit efd4e50

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
configuration settings should now be accessed via `_converse.api.settings.get` and not directly on the `_converse` object.
77
Soon we'll deprecate the latter, so prepare now.
88

9+
- #2231: add sort_by_query and remove sort_by_length
910
- #1313: Stylistic improvements to the send button
1011
- #1481: MUC OMEMO: Error No record for device
1112
- #1490: Busy-loop when fetching registration form fails

spec/autocomplete.js

+47
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,53 @@ describe("The nickname autocomplete feature", function () {
6060
done();
6161
}));
6262

63+
it("should order by query index position and length", mock.initConverse(
64+
['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) {
65+
await mock.openAndEnterChatRoom(_converse, '[email protected]', 'tom');
66+
const view = _converse.chatboxviews.get('[email protected]');
67+
68+
// Nicknames from presences
69+
['bernard', 'naber', 'helberlo', 'john', 'jones'].forEach((nick) => {
70+
_converse.connection._dataRecv(mock.createRequest(
71+
$pres({
72+
'to': '[email protected]/resource',
73+
'from': `[email protected]/${nick}`
74+
})
75+
.c('x', { xmlns: Strophe.NS.MUC_USER })
76+
.c('item', {
77+
'affiliation': 'none',
78+
'jid': `${nick}@montague.lit/resource`,
79+
'role': 'participant'
80+
})));
81+
});
82+
83+
const textarea = view.el.querySelector('textarea.chat-textarea');
84+
const at_event = {
85+
'target': textarea,
86+
'preventDefault': function preventDefault() { },
87+
'stopPropagation': function stopPropagation() { },
88+
'keyCode': 50,
89+
'key': '@'
90+
};
91+
92+
// Test that results are sorted by query index
93+
view.onKeyDown(at_event);
94+
textarea.value = '@ber';
95+
view.onKeyUp(at_event);
96+
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 3);
97+
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('bernard');
98+
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('naber');
99+
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('helberlo');
100+
101+
// Test that when the query index is equal, results should be sorted by length
102+
textarea.value = '@jo';
103+
view.onKeyUp(at_event);
104+
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 2);
105+
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
106+
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
107+
done();
108+
}));
109+
63110
it("autocompletes when the user presses tab",
64111
mock.initConverse(
65112
['rosterGroupsFetched', 'chatBoxesFetched'], {},

src/converse-autocomplete.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,24 @@ export const FILTER_STARTSWITH = function (text, input) {
2222
};
2323

2424

25-
const SORT_BYLENGTH = function (a, b) {
25+
const SORT_BY_LENGTH = function (a, b) {
2626
if (a.length !== b.length) {
2727
return a.length - b.length;
2828
}
2929
return a < b? -1 : 1;
3030
};
3131

32+
const SORT_BY_QUERY_POSITION = function (a, b) {
33+
const query = a.query.toLowerCase();
34+
const x = a.label.toLowerCase().indexOf(query);
35+
const y = b.label.toLowerCase().indexOf(query);
36+
37+
if (x === y) {
38+
return SORT_BY_LENGTH(a, b);
39+
}
40+
return (x === -1 ? Infinity : x) < (y === -1 ? Infinity : y) ? -1 : 1
41+
}
42+
3243

3344
const ITEM = (text, input) => {
3445
input = input.trim();
@@ -147,7 +158,7 @@ export class AutoComplete {
147158
'auto_first': false, // Should the first element be automatically selected?
148159
'data': a => a,
149160
'filter': FILTER_CONTAINS,
150-
'sort': config.sort === false ? false : SORT_BYLENGTH,
161+
'sort': config.sort === false ? false : SORT_BY_QUERY_POSITION,
151162
'item': ITEM
152163
}, config);
153164

0 commit comments

Comments
 (0)