javaeye3/public/javascripts/se_hilite_src.js

140 lines
4.0 KiB
JavaScript

/**
* Search Engine Keyword Highlight (http://fucoder.com/code/se-hilite/)
*
* This module can be imported by any HTML page, and it would analyse the
* referrer for search engine keywords, and then highlight those keywords on
* the page, by wrapping them around <span class="hilite">...</span> tags.
* Document can then define styles else where to provide visual feedbacks.
*
* Usage:
*
* In HTML. Add the following line towards the end of the document.
*
* <script type="text/javascript" src="se_hilite.js"></script>
*
* In CSS, define the following style:
*
* .hilite { background-color: #ff0; }
*
* If Hilite.style_name_suffix is true, then define the follow styles:
*
* .hilite1 { background-color: #ff0; }
* .hilite2 { background-color: #f0f; }
* .hilite3 { background-color: #0ff; }
* .hilite4 ...
*
* @author Scott Yang <http://scott.yang.id.au/>
* @version 1.5
*/
// Configuration:
Hilite = {
/**
* Whether we are matching an exact word. For example, searching for
* "highlight" will only match "highlight" but not "highlighting" if exact
* is set to true.
*/
exact: true,
/**
* Maximum number of DOM nodes to test, before handing the control back to
* the GUI thread. This prevents locking up the UI when parsing and
* replacing inside a large document.
*/
max_nodes: 1000,
/**
* Name of the style to be used. Default to 'hilite'.
*/
style_name: 'hilite',
/**
* Whether to use different style names for different search keywords by
* appending a number starting from 1, i.e. hilite1, hilite2, etc.
*/
style_name_suffix: true
};
/**
* Highlight a DOM element with a list of keywords.
*/
Hilite.hiliteElement = function(elm, query) {
if (!query || elm.childNodes.length == 0)
return;
query = query.split(/[\s,\+\.]+/);
var qre = new Array();
for (var i = 0; i < query.length; i ++) {
query[i] = query[i].toLowerCase();
if (Hilite.exact)
qre.push('\\b'+query[i]+'\\b');
else
qre.push(query[i]);
}
qre = new RegExp(qre.join("|"), "i");
var stylemapper = {};
for (var i = 0; i < query.length; i ++) {
if (Hilite.style_name_suffix)
stylemapper[query[i]] = Hilite.style_name+(i+1);
else
stylemapper[query[i]] = Hilite.style_name;
}
var textproc = function(node) {
var match = qre.exec(node.data);
if (match) {
var val = match[0];
var k = '';
var node2 = node.splitText(match.index);
var node3 = node2.splitText(val.length);
var span = node.ownerDocument.createElement('SPAN');
node.parentNode.replaceChild(span, node2);
span.className = stylemapper[val.toLowerCase()];
span.appendChild(node2);
return span;
} else {
return node;
}
};
Hilite.walkElements(elm.childNodes[0], 1, textproc);
};
Hilite.walkElements = function(node, depth, textproc) {
var skipre = /^(script|style|textarea)/i;
var count = 0;
while (node && depth > 0) {
count ++;
if (count >= Hilite.max_nodes) {
var handler = function() {
Hilite.walkElements(node, depth, textproc);
};
setTimeout(handler, 50);
return;
}
if (node.nodeType == 1) { // ELEMENT_NODE
if (!skipre.test(node.tagName) && node.childNodes.length > 0) {
node = node.childNodes[0];
depth ++;
continue;
}
} else if (node.nodeType == 3) { // TEXT_NODE
node = textproc(node);
}
if (node.nextSibling) {
node = node.nextSibling;
} else {
while (depth > 0) {
node = node.parentNode;
depth --;
if (node.nextSibling) {
node = node.nextSibling;
break;
}
}
}
}
};