Reputation: 53
I'm using the code here: http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
to create a highlight search function, however, the code seems to double wrap the phrase, like so:
<span class="highlight" tabindex="0"><span class="highlight" tabindex="0">Test</span></span>
Can anyone see what i'm missing, i've been on this all day and I think i'm going nuts. Thanks in advance :)
The code that calls the hightlight function is:
<script>
$( document ).ready(function() {
$('.highlightable').removeHighlight().highlight('<?php echo $search['query'] ?>');
<?php if ($search['query']) { ?>
var n = $(".highlightable").find("span.highlight").length;
if (n == 0) {
alert('There are no search results for <?php echo $search['query'] ?>. Please try again.');
} else {
alert('There are ' + n + ' search results for <?php echo $search['query'] ?>. Use TAB key to move between results.');
}
<?php } ?>
});
</script>
Then the function itself:
jQuery.fn.highlight = function(pat) {
function innerHighlight(node, pat) {
var skip = 0;
if (node.nodeType == 3) {
var pos = node.data.toUpperCase().indexOf(pat);
pos -= (node.data.substr(0, pos).toUpperCase().length - node.data.substr(0, pos).length);
if (pos >= 0) {
var spannode = document.createElement('span');
spannode.className = 'highlight';
spannode.tabIndex = '0';
var middlebit = node.splitText(pos);
middlebit.splitText(pat.length);
var middleclone = middlebit.cloneNode(true);
spannode.appendChild(middleclone);
middlebit.parentNode.replaceChild(spannode, middlebit);
skip = 1;
}
}
else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
for (var i = 0; i < node.childNodes.length; ++i) {
i += innerHighlight(node.childNodes[i], pat);
}
}
return skip;
}
return this.length && pat && pat.length ? this.each(function() {
innerHighlight(this, pat.toUpperCase());
}) : this;
};
jQuery.fn.removeHighlight = function() {
return this.find("span.highlight").each(function() {
this.parentNode.firstChild.nodeName;
with (this.parentNode) {
replaceChild(this.firstChild, this);
normalize();
}
}).end();
};
Finished with:
<script>
$( window ).on( "load", function() {
$('.highlight').first().focus();
});
</script>
Upvotes: 0
Views: 1293
Reputation: 11313
The problem you have must have something to do with the environment you're using the code and not the code itself. As you can see in the snippet below, the function works as expected, wrapping the matched word once.
Snippet:
/* ----- JavaScript ----- */
var div = $("div");
function highlight () {
div.highlight("expected");
console.log(div.html());
}
function dehighlight () {
div.removeHighlight();
console.log(div.html());
}
<!----- HTML ----->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//pastebin.com/raw/6zePUJr1"></script>
<style>span.highlight {background-color: #FFFF77}</style>
<button onclick="highlight()">Highlight</button>
<button onclick="dehighlight()">Dehighlight</button>
<div>The code works as expected.</div>
Update:
As mentioned before, both the highlight
and removeHighlight
are not the cause of the problem, as it can be seen in the snippet above. The problem is also not the additional code you've provided (inside the $(document.ready)
function).
Instead, the problem lies in the fact that you have given the class highlightable
to two elements (the following), out of which the former is the parent of the latter:
main.small-12.medium-8.columns.highlightable
div.sections.highlightable
Based on the above, an implication of calling the highlight
function on $(".highlightable")
, is that the search phrase is double-wrapped. First, it is wrapped by being a descendant of the first element and then it is wrapped again, because it's a descendant of the second element as well.
You can easily identify that yourself by typing $(".highlightable").removeHighlight()
in the console. You'll notice that, instead of just the highlight being removed, the entire phrase is.
Also, check out the following snippet. It uses the class highlightable
the same way as you use it in your code which results in double-wrapping the search phrase, just as it happens to you.
Snippet (Faulty):
/* ----- JavaScript ----- */
var highlightable = $(".highlightable");
highlightable.highlight("expected");
console.log(highlightable.last().html());
<!----- HTML ----->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//pastebin.com/raw/6zePUJr1"></script>
<style>span.highlight {background-color: #FFFF77}</style>
<div class = "highlightable">
<p class = "highlightable">
The code doesn't work as expected.
</p>
</div>
Solution:
To fix the double-wrapping issue, you have to remove the class highlightable
from one of the above elements. If that's not an option you can always just use the first element in the jQuery
object:
$('.highlightable').first().removeHighlight().highlight('<?= $search['query'] ?>');
Upvotes: 1