recent_topics: Fix searching for special characters.

Escape all the possible special characters.
We replaced \b with (?:^|\s) since it matches word boundries including
special characters.

Pasted relevant stackoverflow links which expain them properly.
This commit is contained in:
Aman Agrawal
2020-06-26 12:12:35 +05:30
committed by Tim Abbott
parent 7e16650de1
commit 089deb70c9
2 changed files with 40 additions and 5 deletions

View File

@@ -708,3 +708,34 @@ run_test('test_topic_edit', () => {
assert.equal(all_topics.get(get_topic_key(stream2, topic1)), undefined);
verify_topic_data(all_topics, stream3, topic9, messages[0].id, true);
});
run_test('test_search', () => {
const rt = zrequire('recent_topics');
assert.equal(rt.topic_in_search_results('t', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('T', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('to', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('top', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('ToP', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('Topi', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('tOpi', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('toPic', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('Topic', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('topic', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('recent', 'Recent Topic'), true);
assert.equal(rt.topic_in_search_results('RECENT', 'Recent Topic'), true);
// Matches only comple words or from the start of words.
assert.equal(rt.topic_in_search_results('o', 'Recent Topic'), false);
assert.equal(rt.topic_in_search_results('?', 'Recent Topic'), false);
// Test special character match
assert.equal(rt.topic_in_search_results('.*+?^${}()[]\\', 'Recent Topic'), false);
assert.equal(rt.topic_in_search_results('?', 'not-at-start?'), false);
assert.equal(rt.topic_in_search_results('?', '?'), true);
assert.equal(rt.topic_in_search_results('?', '\\?'), false);
assert.equal(rt.topic_in_search_results('\\', '\\'), true);
assert.equal(rt.topic_in_search_results('\\', '\\\\'), true);
});

View File

@@ -215,20 +215,24 @@ exports.process_topic_edit = function (old_stream_id, old_topic, new_topic, new_
exports.process_messages(new_topic_msgs);
};
function topic_in_search_results(keyword, stream, topic) {
exports.topic_in_search_results = function (keyword, stream, topic) {
if (keyword === "") {
return true;
}
// Escape speacial characters from input.
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
keyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// split the search text around whitespace(s).
// eg: "Denamark recent" -> ["Denamrk", "recent"]
const search_keywords = $.trim(keyword).split(/\s+/);
// turn the search keywords into word boundary groups
// eg: ["Denamrk", "recent"] -> "^(?=.*\bDenmark\b)(?=.*\brecent\b).*$"
const val = '^(?=.*\\b' + search_keywords.join('\\b)(?=.*\\b') + ').*$';
// eg: ["Denamrk", "recent"] -> "^(?=.*(?:^|\s)Denmark(?:^|\s))(?=.*(?:^|\s)Recent).*$"
// https://stackoverflow.com/questions/10590098/javascript-regexp-word-boundaries-unicode-characters
const val = '^(?=.*(?:^|\\s)' + search_keywords.join('(?:^|\\s))(?=.*(?:^|\\s)') + ').*$';
const reg = RegExp(val, 'i'); // i for ignorecase
const text = (stream + " " + topic).replace(/\s+/g, ' ');
return reg.test(text);
}
};
function filters_should_hide_topic(topic_data) {
const msg = message_store.get(topic_data.last_msg_id);
@@ -253,7 +257,7 @@ function filters_should_hide_topic(topic_data) {
}
const search_keyword = $("#recent_topics_search").val();
if (!topic_in_search_results(search_keyword, msg.stream, msg.topic)) {
if (!recent_topics.topic_in_search_results(search_keyword, msg.stream, msg.topic)) {
return true;
}