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!
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!
Following solution doesn't work for IE, you'll need to apply TextRange objects etc. for that. As this uses selections to perform this, it shouldn't break the HTML in normal cases, for example:
With
highlight(3,6);
outputs:
Take note how it wraps the first character outside of the span into an
em
, and then the rest within thespan
into a new one. Where as if it would just open it at character 3 and end at character 6, it would give invalid markup like:The code:Example: http://jsfiddle.net/niklasvh/4NDb9/
edit Looks like at least my FF4 had some issues with
but at the same time, it seems to work without it, so I just changed it to
edit as Tim Pointed out, modify is only available from FF4 onwards, so I took a different approach to getting the selection, which doesn't need the modify method, in hopes in making it a bit more browser compatible (IE still needs its own solution).
The code:
example: http://jsfiddle.net/niklasvh/4NDb9/
Based on the ideas of the jQuery.highlight plugin.
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 calldocument.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 tagsHere's a jsFiddle example showing the whole thing, working in all major browsers: http://jsfiddle.net/8mdX4/1211/
And the selection setting code: