ganapati
ganapati

Reputation: 625

How can I highlight the text of the DOM Range object?

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....

Upvotes: 18

Views: 16064

Answers (5)

Harsha Vardhan Chakka
Harsha Vardhan Chakka

Reputation: 1461

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>

Upvotes: 3

Tim Down
Tim Down

Reputation: 324567

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://stackoverflow.com/a/8106283/96100

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);
    }
}

Upvotes: 25

Mark Whitaker
Mark Whitaker

Reputation: 8605

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.

Upvotes: 6

Mandai
Mandai

Reputation: 191

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.

Upvotes: 0

sv_in
sv_in

Reputation: 14039

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

Upvotes: 1

Related Questions