diff --git a/web/src/typeahead_helper.js b/web/src/typeahead_helper.js index 4a71004c6a..07788e71b9 100644 --- a/web/src/typeahead_helper.js +++ b/web/src/typeahead_helper.js @@ -29,16 +29,24 @@ export function build_highlight_regex(query) { } export function highlight_with_escaping_and_regex(regex, item) { + // if regex is empty return entire item highlighted and escaped + if (regex.source === "()") { + return "" + Handlebars.Utils.escapeExpression(item) + ""; + } + // We need to assemble this manually (as opposed to doing 'join') because we need to // (1) escape all the pieces and (2) the regex is case-insensitive, and we need // to know the case of the content we're replacing (you can't just use a bolded // version of 'query') - const pieces = item.split(regex); + const pieces = item.split(regex).filter(Boolean); let result = ""; - for (const piece of pieces) { - if (regex.test(piece)) { + for (let i = 0; i < pieces.length; i += 1) { + const piece = pieces[i]; + if (regex.test(piece) && (i === 0 || pieces[i - 1].endsWith(" "))) { + // only highlight if the matching part is a word prefix, ie + // if it is the 1st piece or if there was a space before it result += "" + Handlebars.Utils.escapeExpression(piece) + ""; } else { result += Handlebars.Utils.escapeExpression(piece); diff --git a/web/tests/typeahead_helper.test.js b/web/tests/typeahead_helper.test.js index b4e10e7a75..4726e303bd 100644 --- a/web/tests/typeahead_helper.test.js +++ b/web/tests/typeahead_helper.test.js @@ -671,6 +671,12 @@ test("highlight_with_escaping", () => { expected = "development help"; result = highlight(query, item); assert.equal(result, expected); + + item = "Prefix notprefix prefix"; + query = "pre"; + expected = "Prefix notprefix prefix"; + result = highlight(query, item); + assert.equal(result, expected); }); test("render_person when emails hidden", ({mock_template}) => {