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:
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>...
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; }
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>...
Comment