We need to add anchors and highlights for some keywords/sentences in the html page. It turns out the highlighting is really slow in Firefox.
In the following code, all ranges which need to be highlighted are stored in array hiliteRanges
:
for (var i = 0; i < hiliteRanges.length; i++){
document.designMode = "on";
var selHilites = window.getSelection();
if (selHilites.rangeCount > 0)
selHilites.removeAllRanges();
selHilites.addRange(hiliteRanges[i]);
var anchorId = 'index'+i;
var insertedHTML = '<span id="' + anchorId + '" style="background-color: #FF8C00;" >'+hiliteRanges[i].toString()+'</span>';
document.execCommand('inserthtml', false, insertedHTML);
document.designMode = "off";
}
Is there any way to speed up the processing? We could have hundreds of ranges in the array hiliteRanges
. We once tried moving the designMode
setting outside of the loop, but we can see some sections are editable in the html page when the loop is running.
There's no need to use document.execCommand()
for this. Just use range methods instead, and then there's no need for designMode
.
var anchorId, hiliteTextNode, hiliteSpan;
for (var i = 0; i < hiliteRanges.length; i++){
// Create the highlight element
hiliteSpan = document.createElement("span");
hiliteSpan.id = anchorId;
hiliteSpan.style.backgroundColor = "#FF8C00";
hiliteTextNode = document.createTextNode(hiliteRanges[i].toString());
hiliteSpan.appendChild(hiliteTextNode);
// Replace the range content
hiliteRanges[i].deleteContents();
hiliteRanges[i].insertNode(hiliteSpan);
}
Also, since ranges are affected by DOM mutation, I would suggest doing this part at the same time as you collect the ranges with window.find()
. Here's an example:
http://jsfiddle.net/YgFjT/
This is my default highlighting snippet and works fine in every browser. Try it out.
Demo: http://jsbin.com/adeneh/1/edit
function highlight(text, words, tag) {
// Default tag if no tag is provided
tag = tag || 'span';
var i, len = words.length, re;
for (i = 0; i < len; i++) {
// Global regex to highlight all matches
re = new RegExp(words[i], 'g');
if (re.test(text)) {
text = text.replace(re, '<'+ tag +' class="highlight">$&</'+ tag +'>');
}
}
return text;
}
// Usage:
var el = document.getElementById('element');
el.innerHTML = highlight(
el.innerHTML,
['word1', 'word2', 'phrase one', 'phrase two', ...]
);
And to unhighlight:
function unhighlight(text, tag) {
// Default tag if no tag is provided
tag = tag || 'span';
var re = new RegExp('(<'+ tag +'.+?>|<\/'+ tag +'>)', 'g');
return text.replace(re, '');
}