How can I highlight the text of the DOM Range object?
Asked Answered
R

5

18

I select some text on the html page(opened in firefox) using mouse,and using javascript functions, i create/get the rangeobject corresponding to the selected text.

 userSelection =window.getSelection(); 
 var rangeObject = getRangeObject(userSelection);

Now i want to highlight all the text which comes under the rangeobject.I am doing it like this,

  var span = document.createElement("span");
  rangeObject.surroundContents(span);
  span.style.backgroundColor = "yellow";

Well,this works fine, only when the rangeobject(startpoint and endpoint) lies in the same textnode,then it highlights the corresponding text.Ex

    <p>In this case,the text selected will be highlighted properly,
       because the selected text lies under a single textnode</p>

But if the rangeobject covers more than one textnode, then it is not working properlay, It highlights only the texts which lie in the first textnode,Ex

 <p><h3>In this case</h3>, only the text inside the header(h3) 
  will be highlighted, not any text outside the header</p> 

Any idea how can i make, all the texts which comes under rangeobject,highlighted,independent of whether range lies in a single node or multiple node? Thanks....

Rugger answered 6/4, 2010 at 5:30 Comment(1)
Possible duplicate: #1623129Graeae
G
25

I would suggest using document's or the TextRange's execCommand method, which is built for just such a purpose, but is usually used in editable documents. Here's the answer I gave to a similar question:

The following should do what you want. In non-IE browsers it turns on designMode, applies a background colour and then switches designMode off again.

UPDATE

Fixed to work in IE 9.

UPDATE 12 September 2013

Here's a link detailing a method for removing highlights created by this method:

https://mcmap.net/q/82497/-remove-highlight-added-to-selected-text-using-javascript

function makeEditableAndHighlight(colour) {
    var range, sel = window.getSelection();
    if (sel.rangeCount && sel.getRangeAt) {
        range = sel.getRangeAt(0);
    }
    document.designMode = "on";
    if (range) {
        sel.removeAllRanges();
        sel.addRange(range);
    }
    // Use HiliteColor since some browsers apply BackColor to the whole block
    if (!document.execCommand("HiliteColor", false, colour)) {
        document.execCommand("BackColor", false, colour);
    }
    document.designMode = "off";
}

function highlight(colour) {
    var range;
    if (window.getSelection) {
        // IE9 and non-IE
        try {
            if (!document.execCommand("BackColor", false, colour)) {
                makeEditableAndHighlight(colour);
            }
        } catch (ex) {
            makeEditableAndHighlight(colour)
        }
    } else if (document.selection && document.selection.createRange) {
        // IE <= 8 case
        range = document.selection.createRange();
        range.execCommand("BackColor", false, colour);
    }
}
Graeae answered 6/4, 2010 at 9:50 Comment(6)
@crizCraig: The selection may have been destroyed by the time the click event fires. You could use the mousedown event instead.Graeae
This will not work in IE if you're trying to fire this on a click of say a highlight button. You just need to save the selection on mouseup using the answer to this question. #5767537Capitation
@crizCraig: Works fine for me in IE in the following simple case: jsfiddle.net/LPnN2Graeae
@TimDown https://mcmap.net/q/82499/-can-39-t-get-text-highlighted-when-multiple-tags-are-present-closed/1503130 I have got stuck in the similar issue hereVirnelli
@Tim Down : how can we undo a selection (highlight) after performing your given code. ?Sommer
@Tim Down : it will remove all the highlights which done using your given code, from the page. So how can it only remove a specific highlight when user select a specific highlighted area. (ex : in PDF's we can highlight and remove highlights as we want. How can we achieve that. The highlighting part is ok. but haw can we do the unhighlighting part as in PDF's here.)Sommer
W
6

Rangy is a cross-browser range and selection library that solves this problem perfectly with its CSS Class Applier module. I'm using it to implement highlighting across a range of desktop browsers and on iPad and it works perfectly.

Tim Down's answer is great but Rangy spares you from having to write and maintain all that feature detection code yourself.

Wheelbarrow answered 9/10, 2012 at 11:30 Comment(1)
I just noticed that Tim Down is the author of Rangy. :)Wheelbarrow
E
3
var userSelection = document.getSelection();
var range = userSelection.getRangeAt(0);

Instead of surroundContent method you can use the appendChild and extractContents methods this way:

let newNode = document.createElement('mark');
newNode.appendChild(range.extractContents());
range.insertNode(newNode);

function markNode() {
if(document.getSelection() && document.getSelection().toString().length){
let range = document.getSelection().getRangeAt(0);
let newNode = document.createElement('mark');
      newNode.appendChild(range.extractContents());
      range.insertNode(newNode);
}
else{
alert('please make selection of text to mark');
}
}

function resetContent() {
      testMe.innerHTML = `Remember: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node">Read</a> and <strong>stay strong</strong>`;
}
<p id="testMe">Remember: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node">Read</a> and <strong>stay strong</strong></p>


<div><button onclick="markNode()">markNode</button></div>
<div><button onclick="resetContent()">resetContent</button></div>
Episternum answered 19/11, 2020 at 10:19 Comment(0)
P
1

Could you please elaborate the need of this functionality. If you only want to change the highlight style of the selected text you can use CSS: '::selection'

More Info: http://www.quirksmode.org/css/selection.html https://developer.mozilla.org/en/CSS/::selection

Pirogue answered 6/4, 2010 at 6:59 Comment(1)
I want to highlight some text permanently (here permanently means till i close the application,quite opposite to what you are suggesting,where when you click somewhere else the 'highlight' vanishes), and dynamically(means i dont want to open html file using text editor and insert some element there)Rugger
M
0

Can you try adding a class for the surrounding span and apply hierarchical CSS?

var span = document.createElement("span");
span.className="selection";
rangeObject.surroundContents(span);

In CSS definition,

span.selection, span.selection * {
   background-color : yellow;  
}

I did not try it. But just guessing that it would work.

Mashhad answered 6/4, 2010 at 9:34 Comment(2)
how do you think that is better than span.style.backgroundColor = "yellow" this?Rugger
Its no different from span.style.background. But the hierarchial CSS I provided "span.selection *" will solve your problem.Mashhad

© 2022 - 2024 — McMap. All rights reserved.