4

I am trying to get highlighting on keyword searching working right. A couple issues I am having.

  1. Case insensitive is working for the first word, but would like it to replace with original case word, not the lowercase searched word.

i.e. search trend, it replaces Trend with trend, I know why, but would like to figure out how to replace back the found word, not the searched word

  1. The second word is not matching case insensitive.

i.e. search trend micro is not matching trend Micro.

Here is jsFiddle: http://jsfiddle.net/hh2zvjft/1/

if ($(".ProjectSearch").val().length > 0) {
    var searchedText = $(".ProjectSearch").val();
    var wordList = searchedText.split(" ");
    $.each(wordList, function (i, word) {
        $(".ProjectTaskGrid:contains('" + word + "')").each(function (i, element) {
            var rgxp = new RegExp(word, "gi");
            var repl = '<span class="search-found">' + word + '</span>';
            element.innerHTML = element.innerHTML.replace(rgxp, repl);
        });
    });
}

Can you please help identify the issues, and offer improvements? Thanks!

Some refererences used to arrive at code:

https://stackoverflow.com/a/120161/2727155

https://stackoverflow.com/a/10011639/2727155

Community
  • 1
  • 1
AdamRoof
  • 264
  • 2
  • 11

2 Answers2

6

Highlight multiple words (ignore HTML tags)

const regEscape = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const EL_input = document.querySelector("#input");
const EL_area = document.querySelector("#area");
const org = EL_area.innerHTML; // Store the current HTML state

const highlight = () => {
  const val = EL_input.value;
  
  if (!val) return EL_area.innerHTML = org;
    
  const pts = regEscape(val.trim()).split(/ +/);
  const reg = new RegExp("(?![^<]+>)(" + pts.join("|") + ")", "ig");
  const res = org.replace(reg, '<span class="highlight">$1</span>');
  
  EL_area.innerHTML = res;
};

EL_input.addEventListener("input", highlight);
highlight();
div {
  padding: 5px;
  border: solid 1px #CCC;
}

.highlight {
  background: gold;
}
<input id="input" autocomplete=off type="text" value="tren pan com br" />

<div id="area">
  Renew Trend Worry-Free Business Security license
  that <a href="http://someweb.com">someweb.com</a> will expire in 60 days.<br>
  Activate BR like breakline trend
  and [ confirm <span>SOME <span>SPAN</span> IS HERE</span>
  upon electronic<br> delivery notification
  from Trend Micro
</div>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • 2
    I love this! Excellent user experience! – Sabrina Oct 07 '15 at 19:50
  • 1
    *shrug* if OP is looking for something that robust they could probably find a plugin to do it. Your solution is pretty awesome for the handful of minutes it took to write it :) – Sabrina Oct 07 '15 at 20:00
  • 1
    I love it too. The downfall is the entire scope of this project was not clear to you all, and I apologize for that, and appreciate the time! Roko's solution is amazing and handles both case insensitive problems. I will definitely learn from this and implement in other features! My find button actually initiates a postback to search on the words in Projects and Tasks from the database, so the keywords aren't there until the page renders from the search results. – AdamRoof Oct 07 '15 at 20:07
  • 1
    @adamRoof even in that case you don't need the Find button :D you simply create a timeout let's say 1second, if the user didn't typed anything until that time > you run your query using the splitted `val` variable. If the user types another character inside the 1s timeout simply clear the timeout and let it tick again. – Roko C. Buljan Oct 07 '15 at 20:15
  • @adam Roof, than on callback success (The server responded with content) you use the `res` variable to highlight the needed words... If I may ask... what are you building? Am I correctly following up with suggestions? – Roko C. Buljan Oct 07 '15 at 20:17
  • I like that suggestion too! I am all for less buttons, giving a clean quick and to the point end user experience! What this is an improvement to and existing Project database with Tasks. The user has a list of tasks within the project they actively work through. The search queries for the keyword from any currently active or completed tasks within that project. – AdamRoof Oct 07 '15 at 20:20
  • 1
    @AdamRoof see this example: http://jsbin.com/fogesi/2/edit?html,css,js,console,output – Roko C. Buljan Oct 07 '15 at 20:44
  • @RokoC.Buljan tell me please how to NOT highlight a part of word if this part less then 3 – Igor Zinchenko Mar 17 '21 at 10:45
1

You were close! Change line 7 to:

var repl = '<span class="search-found">$&</span>';

Notice the $& in there. It's a reference to the matched word and preserves the case.

http://jsfiddle.net/hh2zvjft/2/

And as Roko pointed out in the comment below, you'll get a constant padding increase of 3px on either side if you keep clicking Find. To fix this I'd recommend removing the padding from the CSS, or disabling the Find button if the words have already been highlighted.

Sabrina
  • 617
  • 4
  • 14
  • @RokoC.Buljan, yeah I enjoyed that too. Not really in the scope of the question but I made an edit to my answer to address your observation. – Sabrina Oct 07 '15 at 19:45
  • The padding is not actually increasing, but the number of nested `` elements.... – Roko C. Buljan Oct 07 '15 at 19:56
  • 1
    Right, but the nested spans are still increasing the total padding, if we're getting technical about this. You say tomato, I say solanum lycopersicum :P – Sabrina Oct 07 '15 at 19:57
  • Ahh yes!! Problem 1 solved! I did see the padding increase and was mashing the button to have fun with it too! Not an issue, because my page queries data and the results are rendered on each click. – AdamRoof Oct 07 '15 at 20:10
  • 1
    Thanks @Stef again for the help, in your fiddle as well, the second word doesn't match insensitivitally. micro is not matching Micro. I see Roko doesn't have that issue in his solution, so ill review his and yours and try to combine and figure out why. – AdamRoof Oct 07 '15 at 20:15
  • I up-voted your comment for the invention of `insensitivitally` :D – Sabrina Oct 07 '15 at 20:41