Web Analytics Made Easy -
StatCounter Gecko Find/Highlight Text in page - CodingForum

Announcement

Collapse
No announcement yet.

Gecko Find/Highlight Text in page

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Gecko Find/Highlight Text in page

    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:

    Code:
    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.selectNode(tw.currentNode);
    			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()) {
    			removeAllRanges();
    			addRange(this.findTextMatches.shift());
    		}
    		return true;
    	}
    	else
    		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:

    document.body.highlightText();
    // highlights first occurence

    document.body.highlightText();
    // 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>...
    jasonkarldavis.com

  • #2
    wow

    This is really cool!But I never thougth that it was impossible (being a big Mozilla fan).

    Comment


    • #3
      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.

      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.
      Last edited by jkd; Jul 10, 2002, 01:10 AM.
      jasonkarldavis.com

      Comment


      • #4
        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.

        Comment


        • #5
          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().

          Comment


          • #6
            *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.
            jasonkarldavis.com

            Comment


            • #7
              match whole word doesn't seem to work

              hi all
              ever faced this problem guys ? searching works with optional args but matching whole word doesn't seem to work... sos!
              vrt

              Comment


              • #8
                Originally posted by Bosko
                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.
                *keep it simple (TM)

                Comment


                • #9
                  Originally posted by jkd
                  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.

                  Regards
                  lufa
                  Last edited by lufa; Nov 25, 2005, 10:44 AM.

                  Comment

                  Working...
                  X