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);
   ...