getSelection & surroundContents across multiple tags

I've got a script that changes the background colour of text that has been selected. However i'm encountering an issue when the text is selected across multiple elements/tags.

The code that i've got is:

var text = window.getSelection().getRangeAt(0);
var colour = document.createElement("hlight");
colour.style.backgroundColor = "Yellow";
text.surroundContents(colour);

And the error being output is:

Error: The boundary-points of a range does not meet specific requirements. =
NS_ERROR_DOM_RANGE_BAD_BOUNDARYPOINTS_ERR
Line: 7

I believe this is to do with the getRange() function though i'm not too sure how to proceed since I am a beginner at javascript.

Is there any other way I can replicate what I am trying to achieve?

Many thanks.

Answers:

Answer

This question has been asked today: How can I highlight the text of the DOM Range object?

Here's my answer:

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.

function makeEditableAndHighlight(colour) {
    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, sel;
    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);
    }
}
Answer

Well I think the use of mark.js library is great in this case. The library's intention is to highlight all instances of a certain word in the HTML document, but it can be tweaked through the filter option function, and additional span attributes can be added through the each option function.

function markFunc(node, text, color) {
  var instance = new Mark(node);
    instance.mark(text, {
    "element": "span",
      "className": color,
      "acrossElements": true,
      "separateWordSearch": false,
      "accuracy": "partially",
      "diacritics": true,
      "ignoreJoiners": true,
    "each": function(element) {
            element.setAttribute("id", "sohayb");
            element.setAttribute("title", "sohayb_title");
       },
    "done":function(totalMarks) {
            window.getSelection().empty();//This only in Chrome
            console.log("total marks: " + totalMarks);
     },
      "filter": function(node, term, totalCounter, counter) {
        var res = false;
        if (counter == 0) {
            res = selectionRange.isPointInRange(node, selectionRange.startOffset);
        } else {
        res = selectionRange.isPointInRange(node, 1);
        }
        console.log("Counter: " + counter + ", startOffset: " + selectionRange.startOffset);
        return res;
        }
  });
};

Check this JSFiddle sample for completed code that highlights user's selection, even across multiple HTML elements.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.