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();
A partial solution inspired by Daniel Beck's answer. This solution doesn't manipulate the DOM. (I just displayed the result on the DOM for demonstration purposes)
https://jsfiddle.net/mt2yz90L/3/
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result">
</div>
JS:
let searchedText = 'aa';
let html ='<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';
var htmlParts = html.split(/(<span class="search-text[^>]+>|<\/span>)/g);
var htmlPartsIndex = 0;
for(var i=0; i < htmlParts.length; i++) {
if(htmlParts[i].indexOf('search-text') !== -1) {
htmlPartsIndex = ++i;
break;
}
}
if(htmlPartsIndex > 0) {
htmlParts[htmlPartsIndex] = htmlParts[htmlPartsIndex].toLowerCase().replace(searchedText, '<span class="highlight-text">' + searchedText + '</span>')
}
$('#result').html(htmlParts.join(''));
CSS:
.highlight-text {
background-color: red;
}
My only issue is that in my case (over 300 items to parse) it blocks the browser. So this is quite slow. I posted it in the idea that maybe someone will share a faster solution.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.