I have the following HTML code:
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span>
I want to replace the text between the span tags, but only if the span tag has the class "search-text". So in my case, I have a string containing an HTML code with two spans. I want to replace the text from the second span if it contains a searched text.
I search for: "aa" and I want to replace it with <span class="highlight-text">aa</span>
. So the final result should be:
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-search">AA</span>A</span>
Right now I'm doing something like:
var paint = $.proxy(this._paint, this);
var regex = /(<span class="search-text[^>]+>|<\/span>)/g;
item.node.innerHTML = item.html.replace(regex, paint);
where "value" is: "aa" and "item.html" is the HTML presented at the beginning of my question.
the _paint function:
_paint: function($0) {
return '<span class="highlight-text">' + $0 + '</span>';
},
At this moment the result is that the second span is entirely wrapped into the '<span class="highlight-text">' + $0 + '</span>';
. This is the result:
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="highlight-text"><span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span></span>
I want only the text match to be wrapped inside the hghlight span, like this:
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-text">AA</span>A</span>
Any ideas? Thanks.
Regex is notoriously the wrong tool for most of this job; it's designed for manipulating strings, not structured data such as HTML. Fortunately, you're already in the browser, so you have an entire toolset designed for DOM manipulation available: may as well use it. (You've also tagged the question with jQuery, which makes it even easier.)
Update: I'd misread a detail in the question, and was pulling the search string from a parent node's attribute instead of externally; I also failed to make the search case-insensitive. Both now corrected in the below:
// Make a case-insensitive regex from the search string
let str = 'aa';
let re = new RegExp(str, "gi");
// operate only on the .search-text nodes:
$('.search-text').each(function(i, el) {
// get the current contents of the element:
let text = $(el).html();
// Add your highlights:
text = text.replace(re, '<span class="highlight-text">$&</span>');
// insert the modified text back into the DOM:
$(el).html(text);
})
.highlight-text {
background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span> I
This is only really safe if the .search-text
elements have no child nodes. It will generally work even if they contain some HTML, but only if:
.search-text
wholesale.)For example, trying to highlight the word "span" in an html string containing <span>
elements would result in invalid html:
// same script as above
$('.search-text').each(function(i, el) {
let text = $(el).html();
let highlights = $(el).attr("attribute").split(" ");
for (str of highlights) {
text = text.replace(str, '<span class="highlight-text">' + str + '</span>');
}
$(el).html(text);
})
.highlight-text {
background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="search-text" attribute="span">Text AAA <span>test</span></span>
If your starting point is an HTML string instead of an already-built DOM tree, all you need to do is convert that string into a document fragment first so you can use these DOM tools on it:
let fragment = $('<template>');
fragment.html($yourStringHere);
/* manipulate fragment contents as above, then */
return fragment.html();