Improved highlighting of search flags to handle quotes and flags

Этот коммит содержится в:
hmhealey
2015-11-12 16:53:32 -05:00
родитель 13a251a5ee
Коммит 477b4d3edd

Просмотреть файл

@@ -259,12 +259,89 @@ function autolinkHashtags(text, tokens) {
return output.replace(/(^|\W)(#[a-zA-Z][a-zA-Z0-9.\-_]*)\b/g, replaceHashtagWithToken); return output.replace(/(^|\W)(#[a-zA-Z][a-zA-Z0-9.\-_]*)\b/g, replaceHashtagWithToken);
} }
const puncStart = /^[.,()&$!\[\]{}':;\\]+/;
const puncEnd = /[.,()&$#!\[\]{}':;\\]+$/;
function parseSearchTerms(searchTerm) {
let terms = [];
let termString = searchTerm;
while (termString) {
let captured;
// check for a quoted string
captured = (/^"(.*?)"/).exec(termString);
if (captured) {
termString = termString.substring(captured[0].length);
terms.push(captured[1]);
continue;
}
// check for a search flag (and don't add it to terms)
captured = (/^(?:in|from|channel): ?\S+/).exec(termString);
if (captured) {
termString = termString.substring(captured[0].length);
continue;
}
// capture any plain text up until the next quote or search flag
captured = (/^.+?(?=\bin|\bfrom|\bchannel|"|$)/).exec(termString);
if (captured) {
termString = termString.substring(captured[0].length);
// break the text up into words based on how the server splits them in SqlPostStore.SearchPosts and then discard empty terms
terms.push(...captured[0].split(/[ <>+\-\(\)\~\@]/).filter((term) => !!term));
continue;
}
// we should never reach this point since at least one of the regexes should match something in the remaining text
throw new Error('Infinite loop in search term parsing: ' + termString);
}
// remove punctuation from each term
terms = terms.map((term) => term.replace(puncStart, '').replace(puncEnd, ''));
return terms;
}
function convertSearchTermToRegex(term) {
let pattern;
if (term.endsWith('*')) {
pattern = '\\b' + escapeRegex(term.substring(0, term.length - 1));
} else {
pattern = '\\b' + escapeRegex(term) + '\\b';
}
return new RegExp(pattern, 'gi');
}
function highlightSearchTerm(text, tokens, searchTerm) { function highlightSearchTerm(text, tokens, searchTerm) {
const terms = parseSearchTerms(searchTerm);
if (terms.length === 0) {
return text;
}
let output = text; let output = text;
function replaceSearchTermWithToken(word) {
const index = tokens.size;
const alias = `MM_SEARCHTERM${index}`;
tokens.set(alias, {
value: `<span class='search-highlight'>${word}</span>`,
originalText: word
});
return alias;
}
for (const term of terms) {
// highlight existing tokens matching search terms
var newTokens = new Map(); var newTokens = new Map();
for (const [alias, token] of tokens) { for (const [alias, token] of tokens) {
if (token.originalText.indexOf(searchTerm.replace(/\*$/, '')) > -1) { if (token.originalText === term.replace(/\*$/, '')) {
const index = tokens.size + newTokens.size; const index = tokens.size + newTokens.size;
const newAlias = `MM_SEARCHTERM${index}`; const newAlias = `MM_SEARCHTERM${index}`;
@@ -282,19 +359,10 @@ function highlightSearchTerm(text, tokens, searchTerm) {
tokens.set(newToken[0], newToken[1]); tokens.set(newToken[0], newToken[1]);
} }
function replaceSearchTermWithToken(fullMatch, prefix, word) { output = output.replace(convertSearchTermToRegex(term), replaceSearchTermWithToken);
const index = tokens.size;
const alias = `MM_SEARCHTERM${index}`;
tokens.set(alias, {
value: `<span class='search-highlight'>${word}</span>`,
originalText: word
});
return prefix + alias;
} }
return output.replace(new RegExp(`()(${escapeRegex(searchTerm)})`, 'gi'), replaceSearchTermWithToken); return output;
} }
function replaceTokens(text, tokens) { function replaceTokens(text, tokens) {