Reputation: 1303
I am currently working in native JS and I am trying to build the highlight text feature in a contenteditable div. I have successfully built the highlight feature but I am encountering a problem when I want to toggle between the highlight and unhighlight text using a single button. So I am getting the selected text and the range of the selected text via
var selectedText = window.getSelection();
var range = selectedText.getRangeAt(0);
and I am wrapping the selected text using surroundContents that is a function of range object.
var wrapper = document.createElement("span");
wrapper.setAttribute("class","highlight");
But now when I am trying to unhighlight some part of the highlighted text and some part of plain text the natural behavior should unhighlight the highlighted text and highlight the plain text. To achieve this I am cloning the range via
var clone = range.cloneContents()
var nodeInBetween = clone.childNodes //array of nodes between the start and end nodes.
Now there are two problems I am facing. First I need to remove the span.highlight nodes and replace it with a TextNode again in order to make it unhighlight-ed and I need some method to wrap a textnode with a span. Unfortunately there is no way to wrap a textnode as one can for range variable.
Upvotes: 0
Views: 331
Reputation: 122936
I have experimented with a (recursive) highlighter method in this jsFiddle. It may be of use to you. The actual method:
function highLight(term,root,forElements,styleclass){
root = root || document.querySelector('body');
term = term instanceof Array ? term.join('|') : term;
if (!term) {throw TypeError('Highlighter needs a term to highlight anything');}
forElements = forElements && forElements instanceof Array
? forElements.join(',')
: /string/i.test(typeof forElements) ? forElements : '*';
styleclass = styleclass || 'highlight';
var allDiv = root.querySelectorAll(forElements),
re = RegExp(term,'gi'),
highlighter = function(a){return '<span class="'+styleclass+'">'+a+'</span>'};
for (var i=0; i<allDiv.length; i+=1){
// recurse children
if (allDiv[i].querySelectorAll(forElements).length){
highLight.call(null,term, allDiv[i],forElements,styleclass);
}
// replace term(s) in text nodes
var node = allDiv[i];
for (node=node.firstChild; node; node=node.nextSibling) {
if (node.nodeType===3){
var re = RegExp(term,'gi');
node.data = node.data.replace(re,highlighter);
}
}
}
//finally, replace all text data html encoded brackets
root.innerHTML = root.innerHTML
.replace(/</gi,'<')
.replace(/>/gi,'>');
}
Upvotes: 0