9

I came across this post that shows 2 functions on how to save and restore selected text from a contenteditable div. I have the below div set as contenteditable and the 2 function from the other post. How to i use these functions to save and restore selected text.

<div style="width:300px;padding:10px;" contenteditable="true">test test test test</div>

<script>
function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(range) {
    if (range) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (document.selection && range.select) {
            range.select();
        }
    }
}
</script>
skaffman
  • 398,947
  • 96
  • 818
  • 769
Hussein
  • 42,480
  • 25
  • 113
  • 143
  • You need to use methods of the Range object (see mozilla doc: https://developer.mozilla.org/en/DOM/range ). Basically, a range consists of a node and offset within that node. One way to save the HTML along with the range is to use "carets" (see Closure Library for ideas: http://closure-library.googlecode.com/svn/docs/class_goog_dom_SavedCaretRange.html ). – yonran Jan 14 '11 at 04:55

2 Answers2

21

A typical use would be displaying some kind of widget or dialog to accept input from the user (thus potentially destroying the original selection) and restoring the selection after that widget has been hidden. Actually using the functions is quite simple; the biggest danger is trying to save the selection after it has already been destroyed.

Here's a simple example. It displays a text input and overwrites the selection in the editable <div> with the text from that input. Note that this code has support for Internet Explorer <= 8 in the document.selection branches which could be removed now, in 2022:

function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(range) {
    if (range) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (document.selection && range.select) {
            range.select();
        }
    }
}

function insertTextAtCursor(text) {
    var sel, range, html;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();
            var textNode = document.createTextNode(text) 
            range.insertNode(textNode);
            sel.removeAllRanges();
            range = range.cloneRange();
            range.selectNode(textNode);
            range.collapse(false);
            sel.addRange(range);
        }
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        range.pasteHTML(text);
        range.select();
    }
}

var selRange;

function displayTextInserter() {
    selRange = saveSelection();
    document.getElementById("textInserter").style.display = "block";
    document.getElementById("textToInsert").focus();
}
 

function insertText() {
    var text = document.getElementById("textToInsert").value;
    document.getElementById("textInserter").style.display = "none";
    restoreSelection(selRange);
    document.getElementById("test").focus();
    insertTextAtCursor(text);
}
#textInserter {
    display: none;
}
<div id="test" contenteditable="true">Some editable text</div>
<input type="button" unselectable="on" onclick="displayTextInserter();" value="Insert text">
<div id="textInserter">
    <input type="text" id="textToInsert">
    <input type="button" onclick="insertText()" value="Insert">
</div>
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • +1, I was looking for exactly this solution. Thanks you made my day. – Imran Naqvi Aug 29 '11 at 09:49
  • @TimDown - Tim, how would you use the `saveSelection()` and `restoreSelection(range)` in a way that you can target the `contenteditable div` ? i.e. so it's like saveSelection('mycontentId')` and restoreSelection(range, 'mycontentId') ? I am trying to use it on two seperate 'div's and I need to target each ? Is there any way to incorporate `getElementById` in the two functions so I can target ? – Andy Oct 31 '11 at 13:20
  • @Andy: The selection is bound to the document, not individual elements but there's nothing to stop you saving multiple different selections. Could you give a concrete example of what you'd like to achieve? – Tim Down Oct 31 '11 at 14:25
  • @TimDown - thanks for the response! :) Basically, trying to save by elementId ? So that I could, for example, call and restore it on 2 different elementId's ? i.e. like saveSelection('mycontentId') and then restoreSelection('mycontentId') and then simply enter the elementId that I want to save and restore to use it multiple times ? I would use your awesome plugin rangy - however, I really only need this function and the lib size is probably too big – Andy Nov 02 '11 at 15:06
  • @Andy: Oh, I see what you mean. I think I'd just use a simple object as a hash: something like `var selectionsById = {}; selectionsById['mycontentId'] = saveSelection(); restoreSelection(selectionsById['mycontentId']);`. – Tim Down Nov 02 '11 at 15:19
  • Very good! But how can I use this using a textarea instead the div with id "test"? – DiChrist Oct 25 '17 at 12:25
  • Notice that `document.selection` gives a compilation error in TypeScript because `document.selection` is present in the example specially for IE. – vter Nov 05 '17 at 15:23
  • Genius, you saved my day! – undead10 Apr 27 '22 at 18:15
0

just one recommendation:

it is hard to work with native browser selection + contenteditable + handle all different browser aspects + save and restore selection and etc from scratch..

I would recomend rangy https://code.google.com/p/rangy/wiki/SelectionSaveRestoreModule
that specially done to make all hard work with selection for you

check the docs, it is easy to use ;) hope it will help you

Nedudi
  • 5,639
  • 2
  • 42
  • 37