1

I'm making a simple web-app for fun that lets users select text and highlight it in yellow (or whatever color, doesn't matter). Here is what I have so far:

        function replaceSelectedText() {
            var sel, range;
            var replacementText, spanTag;
            if (window.getSelection) {
                replacementText = window.getSelection().toString();

                spanTag = document.createElement("span");
                spanTag.className = "highlighted";
                spanTag.appendChild(replacementText);

                sel = window.getSelection();
                if (sel.rangeCount) {
                    range = sel.getRangeAt(0);
                    range.deleteContents();
                    //range.insertNode(document.createTextNode(replacementText));
                    range.insertNode(spanTag);
                }
            } else if (document.selection && document.selection.createRange) {
                replacementText = '<span class="highlighted">' + document.selection.createRange().text + '</span>';
                range = document.selection.createRange();
                range.text = replacementText;
            }
        }

        document.onmouseup = replaceSelectedText;
        document.onkeyup = replaceSelectedText;

I had it working where it would highlight the selected phrase, but I was just using a replace() call on the body's HTML so if the user selected a common word like "a", the first occurrence of "a" would be highlighted rather than the one they clicked.

Am I on the right track with the code I have so far, or should I still use the replace() call? Replace seems like it would work, but I can't seem to get the array index of where the selected word occurs, and the range doesn't seem to return a very useful value.

Thanks in advance.

SISYN
  • 2,209
  • 5
  • 24
  • 45
  • What are the browsers you are using ? The below link talks about highlighting on selection and it works for Firefox and Safari: http://stackoverflow.com/questions/2990566/selected-text-background-color – Mehdi Karamosly Dec 20 '12 at 16:02
  • UPDATE: Sorry, now I realize that you have to click the check mark button below the arrows to accept an answer. I have gone back and accepted all the good responses to my questions, sorry I didn't know how to do this sooner! – SISYN Dec 20 '12 at 19:09
  • If you want to highlight selected text, you can do this using `document.execCommand()`. See http://stackoverflow.com/questions/2582831/how-can-i-highlight-the-text-of-the-dom-range-object – Tim Down Dec 20 '12 at 23:31

3 Answers3

1

You can get a reference to the specific node you're on via getSelection().baseNode. It gives you the index and length of selection as well so you can replace the exact text instead of doing a replace.

Snuffleupagus
  • 6,365
  • 3
  • 26
  • 36
1

I don't see any problem with this approach beside the fact that you should also get the position of the cursor to replace your selection you probably should use like is the case in this post:

$("#myTextInput").bind("keydown keypress mousemove", function() {
  alert("Current position: " + $(this).caret().start);
});

jQuery: Get the cursor position of text in input without browser specific code?

Community
  • 1
  • 1
Mehdi Karamosly
  • 5,388
  • 2
  • 32
  • 50
  • That's only for text inputs and textareas. I think the question is about highlighting text within the regular content of the page. – Tim Down Dec 20 '12 at 23:27
  • @TimDown this is the link for a div implementation with jquery caret : http://stackoverflow.com/questions/2871081/jquery-setting-cursor-position-in-contenteditable-div – Mehdi Karamosly Dec 21 '12 at 00:07
0

use http://code.google.com/p/rangy/

To replace selected text add event on mouse up with following code

 var el = $("<span></span>");
el.text(rangy.getSelection().getRangeAt(0).toString());
 rangy.getSelection().getRangeAt(0).deleteContents();
 rangy.getSelection().getRangeAt(0).insertNode(el.get(0));
 rangy.getSelection().getRangeAt(0).getSelection().setSingleRange(range);
Vova Bilyachat
  • 18,765
  • 4
  • 55
  • 80