I am currently trying to code a Javascript Chrome extension to highlight some words and add their definitions within a tooltip. Everything seems to work except that certain definitions that I want to add also contain words that are supposed to be highlighted on the original page. The result is a kind of loop: some words within the tooltip are highlighted and a new tooltip is created over the first one and so on.
I first mapped all the words I wanted to replace as regular expressions and stored them with the corresponding HTMT to replace it :
span class='tooltip'>the<span class='tooltipcontent'>This is a test to check if this extension works and shows this content as a tooltip.</span></span>
I then used a treewalker to get the nodes I was interested in (the text nodes) and stored them in a list :
So the problem actually is that I get several tooltip when I should just get one if on word of the list is in it. I totally understand where this comes from but I donât really know how to avoid it. I have tried to skip the nodes with the class name âtooltipâ or âtooltipcontentâ but it does not seem to work. I have also tried to skip the nodes which the inner HTML contains the word âtooltipâ or âtooltipcontentâ but with no result.
I usually try my best to find a solution on my own but this time I feel that I miss something simple and I canât figure out what. Would anyone be able to help me find a solution on that ?
Hi @mattertonn, can you provide some dummy values for glossary and rgx so we can reproduce the issue? BTW you have a couple of implicit globals in your code⌠thatâs probably not causing the bug in question, but should still be avoided (and would throw an error in strict mode).
Here is values for glossary and their regex equivalent for rgx :
let glossary = new Map();
glossary.set('the'," <span class='tooltip'>the<span class='tooltipcontent'>This is a test to check if this extension works and shows this content as a tooltip.</span></span> ");
glossary.set('it', " <span class='tooltip'>it<span class='tooltipcontent'>This is a test to check if this extension works and shows this content as a tooltip.</span></span> ");
glossary.set('a', " <span class='tooltip'>la<span class='tooltipcontent'>This is a test to check if this extension works and shows this content as a tooltip.</span></span> ");
glossary.set('to', " <span class='tooltip'>not<span class='tooltipcontent'>This is a test to check if this extension works and shows this content as a tooltip.</span></span> ");
let rgx = new Map();
for(let word of glossary.keys()){
let r = "\\W+("+word+")\\W+";
rgx.set(word, new RegExp(r, 'gi'));
}
And also thanks for having spotted the implicit globals, I will fix that. To be frank I was expecting this issue since the beginning but still my lack of experience keeps my away from bypassing it.
Thanks! Well the problem is that inside the for ... of loop, youâre potentially updating the content several times but without verifying again that the matched content isnât child of a tooltip. A possible solution would be to return (or break) from the loop after the first replacement, and then walk the newly created span again:
or, considering the regex works on word boundaries (which, incidentally, will cause the script to collapse on any non-English websiteâŚ), explode the content on the boundaries and instead of doing a regex do a map function to do direct comparison on word-for-word.