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/t
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);
}
}
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.