/* Search highlight support */ var firstMatch=null; /* Returns an elements absolute position, allowing for the non-scrolling header */ function getElementPosition(e) { var offsetLeft = 0; var offsetTop = 0; while (e) { // Allow for the scrolling body region in IE if (msieversion() > 4) { offsetLeft += (e.offsetLeft - e.scrollLeft); offsetTop += (e.offsetTop - e.scrollTop); } else { offsetLeft += e.offsetLeft ; offsetTop += e.offsetTop; } e = e.offsetParent; } if (navigator.userAgent.indexOf('Mac') != -1 && typeof document.body.leftMargin != 'undefined') { offsetLeft += document.body.leftMargin; offsetTop += document.body.topMargin; } return {left:offsetLeft,top:offsetTop}; } /* Return Microsoft Internet Explorer (major) version number, or 0 for others. */ function msieversion() { var ua = window.navigator.userAgent; var msie = ua.indexOf ( "MSIE " ); if ( msie > 0 ) // is Microsoft Internet Explorer; return version number { return parseInt ( ua.substring ( msie+5, ua.indexOf ( ".", msie ) ) ); } else { return 0; // is other browser } } /* Highlight text in a document */ function HighlightText(targetDocument,text,color,backColor,clearBefore) { if(clearBefore) { firstMatch=null; removeAllHighlights(targetDocument); } if(text != "") { HighlightTextInElement(targetDocument,targetDocument.body,text,color,backColor,firstMatch); // Scroll to the first hit if it's not already visible if(firstMatch && clearBefore) { if(getElementPosition(firstMatch).top > targetDocument.documentElement.scrollTop+targetDocument.documentElement.clientHeight || getElementPosition(firstMatch).top < targetDocument.documentElement.scrollTop) { targetDocument.documentElement.scrollTop = firstMatch.offsetTop; } } } } /* Highlight text in a specific element */ function HighlightTextInElement(targetDocument,element,text,color,backColor) { var lowerCaseText = text.toLowerCase(); var node=null; var nodeText=null; var lowerCaseNodeText=null; var highlightSpan=null; var remainingText=null; var textNode=null; var selection=null; // Traverse the document backwards otherwise the DOM returns stale objects as // we make modifications for(var x=element.childNodes.length-1;x>=0;x--) { node = element.childNodes[x]; // Text Node if(node.nodeType == 3) { nodeText = node.nodeValue; lowerCaseNodeText = nodeText.toLowerCase(); for(pos=lowerCaseNodeText.indexOf(lowerCaseText);pos>=0;pos=lowerCaseNodeText.indexOf(lowerCaseText)) { // Create a span to mark up the highlight highlightSpan = targetDocument.createElement("SPAN"); highlightSpan.style.backgroundColor = backColor; highlightSpan.style.color = color; highlightSpan.className = "InnovasysSearchHighlight"; highlightSpan.appendChild(targetDocument.createTextNode(nodeText.substring(pos,pos+text.length))); // Insert the span containing the term remainingText = targetDocument.createTextNode(nodeText.substring(pos+text.length,nodeText.length)); node.nodeValue = nodeText.substring(0,pos); highlightSpan = node.parentNode.insertBefore(highlightSpan,node.nextSibling); remainingText = node.parentNode.insertBefore(remainingText,highlightSpan.nextSibling); // Store the first (last)hit so we can scroll to it firstMatch = highlightSpan; // Skip past the new nodes we've added node = node.nextSibling.nextSibling; nodeText = node.nodeValue; lowerCaseNodeText = nodeText.toLowerCase(); } } // Element node else if(node.nodeType == 1) { // To ensure we don't modify script or go over // highlights we have already applied if(node.nodeName != "SCRIPT" && !(node.nodeName == "SPAN" && node.className == "InnovasysSearchHighlight")) { HighlightTextInElement(targetDocument,node,text,color,backColor); } } } } /* Returns all highlight SPAN elements for a document */ function getHighlightSpans(targetDocument) { var spans=targetDocument.getElementsByTagName("SPAN"); var highlightSpans = new Array(); var span=null; var highlightSpanCount=0; for(x=spans.length-1;x>=0;x--) { span = spans[x]; if(span.className == "InnovasysSearchHighlight") { highlightSpans[highlightSpanCount] = span; highlightSpanCount++; } } return highlightSpans; } /* Merges any adjacent text node.s The IE DOM in particular has a habit of splitting up text nodes, and also after highlighting and removing split adjacent nodes can be left */ function cleanUpTextNodes(parentNode) { var node=null; var lastNode=null; var mergeCount=null; do { mergeCount=0; for(var x=1;x0) for(var x=0;x=0;x--) { span = spans[x]; text = targetDocument.createTextNode(span.innerHTML); span.parentNode.replaceChild(text,span); } // This process may have resulted in multiple contiguous text nodes // which could cause problems with subsequent search highlight operations // So we join any continguous text nodes here cleanUpTextNodes(targetDocument.body); }