I would like to highlight (apply css to) a certain text range, denoted by its start and end position. This is more diffucult than it seems, since there may be other tags within the text, that need to be ignored.
Example:
<div>abcd<em>efg</em>hij</div>
highlight(2, 6)
needs to highlight "cdef
" without removing the tag.
I have tried already using a TextRange object, but without success.
Thanks in advance!
Highlight Text Using the Mark Tag Method in JavaScriptIf you surround any text inside the mark tag, the browser will automatically highlight it in a striking yellow color. This will make highlighting a searched text quite a simple task then.
The <mark> tag in HTML is used to define the marked text. It is used to highlight the part of the text in a paragraph.
You can't actually highlight text in a <textarea> . Any markup you would add to do so would simply display as plain text within the <textarea> . The good news is, with some carefully crafted CSS and JavaScript, you can fake it.
Below is a function to set the selection to a pair of character offsets within a particular element. This is naive implementation: it does not take into account any text that may be made invisible (either by CSS or by being inside a <script>
or <style>
element, for example) and may have browser discrepancies (IE versus everything else) with line breaks, and takes no account of collapsed whitespace (such as 2 or more consecutive space characters collapsing to one visible space on the page). However, it does work for your example in all major browsers.
For the other part, the highlighting, I'd suggest using document.execCommand()
for that. You can use my function below to set the selection and then call document.execCommand()
. You'll need to make the document temporarily editable in non-IE browsers for the command to work. See my answer here for code: getSelection & surroundContents across multiple tags
Here's a jsFiddle example showing the whole thing, working in all major browsers: http://jsfiddle.net/8mdX4/1211/
And the selection setting code:
function getTextNodesIn(node) {
var textNodes = [];
if (node.nodeType == 3) {
textNodes.push(node);
} else {
var children = node.childNodes;
for (var i = 0, len = children.length; i < len; ++i) {
textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
}
}
return textNodes;
}
function setSelectionRange(el, start, end) {
if (document.createRange && window.getSelection) {
var range = document.createRange();
range.selectNodeContents(el);
var textNodes = getTextNodesIn(el);
var foundStart = false;
var charCount = 0, endCharCount;
for (var i = 0, textNode; textNode = textNodes[i++]; ) {
endCharCount = charCount + textNode.length;
if (!foundStart && start >= charCount
&& (start < endCharCount ||
(start == endCharCount && i <= textNodes.length))) {
range.setStart(textNode, start - charCount);
foundStart = true;
}
if (foundStart && end <= endCharCount) {
range.setEnd(textNode, end - charCount);
break;
}
charCount = endCharCount;
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.selection && document.body.createTextRange) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(true);
textRange.moveEnd("character", end);
textRange.moveStart("character", start);
textRange.select();
}
}
You could take a look at how works this powerful JavaScript utility which support selection over multiple DOM elements:
MASHA (short for Mark & Share) allow you to mark interesting parts of web page content and share it
http://mashajs.com/index_eng.html
It's also on GitHub https://github.com/SmartTeleMax/MaSha
Works even on Mobile Safari and IE!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With