Recombine broken-up text in paragraph and find chosen text
Starting from the bottom of the code, the main .each() block iterates through each paragraph at a time and firstly gets rid of any highlighted text from a previous usage, gathers each textNode and then splits each into precisely one textNode per character, relists each textNode (each one char long), then matches each letter where there's a match to the selected word and highlights each of those characters. I borrowed some ideas from jQuery/Sizzle .text() method for my getTextOnly() function.
by alano
HTML
<div id="myFrame">
<p>W<span class="a">o</span><span class="b">rd</span> One</p>
<p><span class="a">An<strong>o</strong><em>t</em>h</span><span class="b">er Sen</span><span class="c">te<em>nc</em>e</span></p>
</div>
<div>
<input id="findText" type="text" placeholder="Enter text to find..." />
<button onclick="doIt()">Search</button>
</div>
CSS
div#myFrame { border: 1px solid Black; }
span.HL { background-color: Yellow; }
#myFrame span.a { color: Red; }
#myFrame span.b { color: Green; }
#myFrame span.c { color: Blue; }
JavaScript
function doIt() {
var $frame = $("#myFrame");
var sText = $("#findText").val().trim().toLowerCase();
var sLen = sText.length;
var getTextNodes = function (elem) {
var ret = [];
return getTextOnly(elem);
function getTextOnly(elem) {
//borrowed, in part, from jQuery's Sizzle engine
var node, i = 0, nodeType = elem.nodeType;
if (nodeType) {
if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
// Traverse children
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
getTextOnly(elem);
}
} else if (nodeType === 3 || nodeType === 4) {
return ret.push(elem);
}
// Do not include comment or processing instruction nodes
} else {
// If no nodeType, this is expected to be an array
for (; (node = elem[i]); i++) {
// Do not traverse comment nodes
getTextOnly(node);
}
}
return ret;
}
};
function splitFrags(frags) {
$(frags).each(function () {
for (var i = 0; i < this.length; i++) {
var letter = this.nodeValue.substr(i, 1);
var frag = document.createTextNode(letter);
this.parentNode.insertBefore(frag, this);
}
this.parentNode.removeChild(this);
});
}
function hiliteFrag(frag) {
var newText = frag.cloneNode();
var span = document.createElement("span");
span.setAttribute("class", "HL");
span.appendChild(newText);
frag.parentNode.replaceChild(span, frag);
}
$("p", $frame).each(function () {
$("span.HL", $(this)).removeClass("HL"); //remove hilites incase already run previously
var textFrags = getTextNodes(this);
...