View Full Version : Gecko Find/Highlight Text in page

07-09-2002, 08:34 PM
People have complained that window.find() doesn't work, and everyone knows Gecko doesn't support IE's proprietary TextRange object, some have assumed you can't do this in Gecko.

On the contrary though:

Node.prototype.findTextMatches = [];

Node.prototype.findText = function(query, ignoreCase) {
this.findTextMatches.length = 0;
if (ignoreCase)
query = query.toLowerCase();

var tw = this.ownerDocument.createTreeWalker(this, NodeFilter.SHOW_TEXT, { acceptNode: function(node) { return NodeFilter['FILTER_' + (RegExp(query, (ignoreCase ? 'i' : '')).test(node.nodeValue) ? 'ACCEPT' : 'REJECT')] } }, true);
var offsets = [];
offsets[-1] = query.length * -1;
var totalMatches, trueOffsetDiff;
var range = this.ownerDocument.createRange();

while (tw.nextNode()) {
totalMatches = tw.currentNode.nodeValue.split(RegExp(query, (ignoreCase ? 'i' : ''))).length - 1;
for (var i = 0; i < totalMatches; i++) {
trueOffsetDiff = offsets[offsets.length - 1] + query.length;
offsets[offsets.length] = tw.currentNode.nodeValue.substr(trueOffsetDiff)[ignoreCase ? 'toLowerCase' : 'toString']().indexOf(query) + trueOffsetDiff;

range.setStart(tw.currentNode, offsets[offsets.length - 1]);
range.setEnd(tw.currentNode, range.startOffset + query.length);
this.findTextMatches[this.findTextMatches.length] = range.cloneRange();
offsets.length = 0;
return (tw.currentNode != this);

Node.prototype.highlightText = function() {
if (this.findTextMatches.length > 0) {
with (window.getSelection()) {
return true;
return false;

To search all text in the body, ignoring case, you'd go like:

document.body.findText('search query', true);

That loads up an array full of ranges selecting the text into document.body.findTextMatches.

To selectively highlight next occurences after executing findText:

// highlights first occurence

// removes previous selection, highlights second occurrence

// etc

Just calling that method over and over will successfully highlight instances. It returns true if it highlighted something, false otherwise,

Also, since I prototyped Node, it works not just in HTML documents, but can work in XML documents too.

Calling document.findText in an HTMLDocument may cause interesting results, as it searches through all the nodes, including <head>...

07-09-2002, 09:23 PM
This is really cool!But I never thougth that it was impossible (being a big Mozilla fan).

07-10-2002, 07:05 AM
Bah, much to my embarassment, I discovered on an IDL rampage I was having at lxr.mozilla.org this:

The reason window.find() never seemed to work was that we never supplied it enough arguments. :D

window.find('search query', caseSensitive, searchBackwards, wrapAround, wholeWord, searchInFrames, showDialog)

A string, followed by 6 booleans.

An equivalent statement to all that code above is:

window.find('search string', caseSensitive, false, false, false, false, false)

But that searches the entire window... my code can selectively search the text od certain nodes. :D

07-10-2002, 04:41 PM
So,the find() function of Mozilla is way more powerfull than the find() function of IE :)
I find it very handy that I can open the find dialog too.

07-12-2002, 08:27 PM
Hi. I've neen trying to run your findText script in Netscape 6. If I try:

win = parent.frames[1]
win.document.body.findText(str, true)

...I get findText() function not found. Isn't there a way to define findText for a parent.frames[1]? If I try just:

document.body.findText(str, true)

...I get NodeFilter not found. Where is NodeFilter defined?

I've tried win.find(str,true), which comes back find() function not found. I don't believe NS6 has find().

07-13-2002, 12:22 AM
*sigh* No need to both email me and post a reply here. This is definitely the more important area, as others can see it.

From the email I replied with so others can see it:

It doesn't work in early versions of NS6. I use the recently implemented TreeWalker interface and NodeFilter to iterate through possible text nodes. I know for sure NS7 PR and above supports it, and the latest NS6 build *might*. I always write my scripts in a version of Mozilla (what NS6+ is based on) never outdated by a week, so a lot of stuff will not work in NS6.

07-20-2005, 06:39 AM
hi all
ever faced this problem guys ? searching works with optional args but matching whole word doesn't seem to work... sos!

07-22-2005, 10:50 AM
I find it very handy that I can open the find dialog too.

you'll be able to do that in IE, too, no doubt. a quick search on MSDN should be able to confirm or refute that. :thumbsup: :cool:

11-25-2005, 01:52 PM
window.find('search query', caseSensitive, searchBackwards, wrapAround,
wholeWord, searchInFrames, showDialog)
In case there is no search result I want to inform the user with
an appropriate message, but the above mentionend window.find(...)
never returns false because one search result is the text in the input field.

Anyone noticed that behaviour? Is there a workaround except not
using this method?

BTW: Using your script I wondered if it is possible to jump to the selection
the same way the standard find() is doing this.