Всё таки решил я эту задачу, но не полностью. Честно говоря, решение мне то же не очень нравится, очень похоже на "подгонку на ответ", но других мыслей пока не появилось.
В данном решении поиск фразы (например, "body Any text") производится по всему тексту и находит все, кроме 2 мест. В коде так же есть часть закоментированноого кода, которая, если её раскомментировать, находит все вхождения, но выделяет найденный текст со смещением. Как это побороть?
<html>
<head>
<title>Search Text</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<script language="javascript">
function getTextNodeList(parentNode,list){
for(var a=0;a<parentNode.childNodes.length;a++){
if(parentNode.childNodes[a].nodeType==3){
if(parentNode.childNodes[a].nodeValue.length==1&&parentNode.childNodes[a].nodeValue==="\n")
continue;
else
list.push({
n: parentNode.childNodes[a],
s: list[list.length-1]?parseInt(list[list.length-1].s)+parseInt(list[list.length-1].l):0,
l: parentNode.childNodes[a].length
});
}else{
getTextNodeList(parentNode.childNodes[a],list);
}
}
}
var storage={
srch: '',
lastIdx: -1,
result: new Array(),
clear: function(){
with(storage){
srch='';
lastIdx=-1;
result=new Array();
}
},
search: function(){
if(storage.srch!==''){
var b=document.body;
var list=new Array();
getTextNodeList(b,list);
var r=document.createRange();
r.selectNodeContents(b);
var c='';
var v=null;
for(var a=0;a<list.length;a++){
v=list[a].n.nodeValue;
c+=v.replace(/\n/gim," ");
/*
* Если раскомментировать этот блок, ищет все фразы
* но "со смещением"
if(v.charAt(v.length-1)!==" "&&v.charAt(v.length-1)!=="\n"){
console.log('"'+v+'"');
c+=' ';
}
*/
}
console.log(c);
var p=new RegExp(storage.srch,"ig");
var data=null;
var startContainer=null;
var startOffset=0;
var endContainer=null;
var endOffset=0;
var start=0;
var end=0;
var ls=0;
var ll=0;
while((data=p.exec(c))!=null){
start=p.lastIndex-storage.srch.length;
end=p.lastIndex;
for(var a=0;a<list.length;a++){
ls=parseInt(list[a].s);
ll=ls+parseInt(list[a].l);
if(start>=ls&&start<ll){
startContainer=list[a].n;
startOffset=start-ls;
}
if(end>=ls&&end<ll){
endContainer=list[a].n;
endOffset=end-ls;
}
}
storage.result.push({
sc: startContainer,
so: startOffset,
ec: endContainer,
eo: endOffset
});
}
}
},
init: function(){
storage.clear();
if(arguments[0])
with(storage){
srch=arguments[0];
search();
}
}
};
function findNext(){
var i=document.getElementById('srchText');
if(storage.result.length==0 || (storage.srch!==i.value && i.value!=='')){
storage.init(i.value);
}
if(storage.result.length>0){
var s=null;
var r=null;
// for Gecko only
if(window.getSelection){
var s=window.getSelection();
var r=document.createRange();
storage.lastIdx++;
if(storage.lastIdx>storage.result.length-1)
storage.lastIdx=0;
r.setStart(storage.result[storage.lastIdx].sc,storage.result[storage.lastIdx].so);
r.setEnd(storage.result[storage.lastIdx].ec,storage.result[storage.lastIdx].eo);
s.removeAllRanges();
s.addRange(r);
}
}else{
alert('Совпадений не найдено');
}
}
</script>
</head>
<body>
Any text into body Any text into body
<div>Any text into body Any text into body <span>Any text into body Any text into body <span>Any text into body Any text into body</span></span></div>
<div>Any text into body Any text into body</div>
<span>Any text into body Any text into body</span>
Any text into body Any text into body
<br />
<input id="srchText" type="text" value="" /><input type="button" value="Search" onclick="findNext()" />
</body>
</html>