11

Is it possible to use Javascript in Safari/Firefox/Chrome to search a particular div container for a given text string. I know you can use window.find(str) to search the entire page but is it possible to limit the search area to the div only?

Thanks!

dhh
  • 4,289
  • 8
  • 42
  • 59
101010110101
  • 1,940
  • 8
  • 31
  • 42

8 Answers8

7

Once you look up your div (which you might do via document.getElementById or any of the other DOM functions, various specs here), you can use either textContent or innerText to find the text of that div. Then you can use indexOf to find the string in that.

Alternately, at a lower level, you can use a recursive function to search through all text nodes in the window, which sounds a lot more complicated than it is. Basically, starting from your target div (which is an Element), you can loop through its childNodes and search their nodeValue string (if they're Texts) or recurse into them (if they're Elements).

The trick is that a naive version would fail to find "foo" in this markup:

<p><span>fo</span>o</p>

...since neither of the two Text nodes there has a nodeValue with "foo" in it (one of them has "fo", the other "o").

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    I'm actually looking to replicate the browser find functionality (the string would be highlighted and upon clicking search one more time it would move on down to the next match inside of the Div, etc). – 101010110101 Feb 28 '13 at 18:11
  • 1
    @VeePee: I'm afraid you'd have to write it (which is possible, just a real pain), even `window.find` isn't standardized. But again, it's possible, because you can find the text in the `Text` node, split that node to surround it with a highlighting `span`, etc., etc. – T.J. Crowder Feb 28 '13 at 18:12
3

Depending on what you are trying to do, there is an interesting way of doing this that does work (does require some work).

First, searching starts at the location where the user last clicked. So to get to the correct context, you can force a click on the div. This will place the internal pointer at the beginning of the div.

Then, you can use window.find as usual to find the element. It will highlight and move toward the next item found. You could create your own dialog and handle the true or false returned by find, as well as check the position. So for example, you could save the current scroll position, and if the next returned result is outside of the div, you restore the scroll. Also, if it returns false, then you can say there were no results found.

You could also show the default search box. In that case, you would be able to specify the starting position, but not the ending position because you lose control.

Some example code to help you get started. I could also try putting up a jsfiddle if there is enough interest.

Syntax:

window.find(aStringToFind, bCaseSensitive, bBackwards, bWrapAround, bWholeWord, bSearchInFrames, bShowDialog);

For example, to start searching inside of myDiv, try

document.getElementById("myDiv").click(); //Place cursor at the beginning
window.find("t", 0, 0, 0, 0, 0, 0); //Go to the next location, no wrap around

You could set a blur (lose focus) event handler to let you know when you leave the div so you can stop the search.

To save the current scroll position, use document.body.scrollTop. You can then set it back if it trys to jump outside of the div.

Hope this helps! ~techdude

techdude
  • 1,334
  • 20
  • 29
1

As per the other answer you won't be able to use the window.find functionality for this. The good news is, you won't have to program this entirely yourself, as there nowadays is a library called rangy which helps a lot with this. So, as the code itself is a bit too much to copy paste into this answer I will just refer to a code example of the rangy library that can be found here. Looking in the code you will find

 searchScopeRange.selectNodeContents(document.body);

which you can replace with

 searchScopeRange.selectNodeContents(document.getElementById("content"));

To search only specifically in the content div.

David Mulder
  • 26,123
  • 9
  • 51
  • 114
1

If you are still looking for someting I think I found a pretty nice solution;

Here it is : https://www.aspforums.net/Threads/211834/How-to-search-text-on-web-page-similar-to-CTRL-F-using-jQuery/

And I'm working on removing jQuery (wip) : codepen.io/eloiletagant/pen/MBgOPB Hope it's not too late :)

eloiletagant
  • 1,351
  • 2
  • 8
  • 13
1

You can make use of Window.find() to search for all occurrences in a page and Node.contains() to filter out unsuitable search results.
Here is an example of how to find and highlight all occurrences of a string in a particular element:

var searchText = "something"
var container = document.getElementById("specificContainer");
// selection object
var sel = window.getSelection()
sel.collapse(document.body, 0)
// array to store ranges found
var ranges = []
// find all occurrences in a page
while (window.find(searchText)) {
    // filter out search results outside of a specific element
    if (container.contains(sel.anchorNode)){
        ranges.push(sel.getRangeAt(sel.rangeCount - 1))
    }
}   
// remove selection
sel.collapseToEnd()

// Handle ranges outside of the while loop above.
// Otherwise Safari freezes for some reason (Chrome doesn't).
if (ranges.length == 0){
    alert("No results for '" + searchText + "'")
 } else {
    for (var i = 0; i < ranges.length; i++){
        var range = ranges[i]
        if (range.startContainer == range.endContainer){
            // Range includes just one node
            highlight(i, range)
        } else {
            // More complex case: range includes multiple nodes
            // Get all the text nodes in the range
            var textNodes = getTextNodesInRange(
                                range.commonAncestorContainer,
                                range.startContainer,
                                range.endContainer) 

            var startOffset = range.startOffset
            var endOffset = range.endOffset
            for (var j = 0; j < textNodes.length; j++){
                var node = textNodes[j]
                range.setStart(node, j==0? startOffset : 0)
                range.setEnd(node, j==textNodes.length-1? 
                                       endOffset : node.nodeValue.length)
                highlight(i, range)
            }
        }
    }
}

function highlight(index, range){
    var newNode = document.createElement("span")
    // TODO: define CSS class "highlight"
    // or use <code>newNode.style.backgroundColor = "yellow"</code> instead
    newNode.className = "highlight"
    range.surroundContents(newNode)
    // scroll to the first match found
    if (index == 0){
        newNode.scrollIntoView()
    }
}

function getTextNodesInRange(rootNode, firstNode, lastNode){
    var nodes = []
    var startNode = null, endNode = lastNode
    var walker = document.createTreeWalker(
            rootNode,
            // search for text nodes
            NodeFilter.SHOW_TEXT,
            // Logic to determine whether to accept, reject or skip node.
            // In this case, only accept nodes that are between
            // <code>firstNode</code> and <code>lastNode</code>
            {
                acceptNode: function(node) {
                    if (!startNode) {
                        if (firstNode == node){
                            startNode = node
                            return NodeFilter.FILTER_ACCEPT
                        }
                        return NodeFilter.FILTER_REJECT
                    }

                    if (endNode) {
                        if (lastNode == node){
                            endNode = null
                        }
                        return NodeFilter.FILTER_ACCEPT
                    }

                    return NodeFilter.FILTER_REJECT
                 }
            },
            false
        )

    while(walker.nextNode()){
        nodes.push(walker.currentNode);
    }
    return nodes;
}

For the Range object, see https://developer.mozilla.org/en-US/docs/Web/API/Range.
For the TreeWalker object, see https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker

0
var elements = [];
$(document).find("*").filter(function () {
  if($(this).text().contains(yourText))
    elements.push($(this));
});
console.log(elements);

I didn't try it, but according the jQuery documentation it should work.

iamawebgeek
  • 2,713
  • 1
  • 18
  • 34
0

Here is how I am doing with jquery:

var result = $('#elementid').text().indexOf('yourtext') > -1

it will return true or false

Miraj
  • 326
  • 3
  • 17
-2

Maybe you are trying to not use jquery...but if not, you can use this $('div:contains(whatyouarelookingfor)') the only gotcha is that it could return parent elements that also contain the child div that matches.

JoelH
  • 25
  • 1