9

Is it possible to (reliably) get the selected text/caret position in a input text box if that field doesn't have focus?

If not, what's the best way to get and retain this data?

Basically, when a user clicks a button I want to insert some text at the caret position. However, as soon as the user clicks that button, the field loses focus and I lose the caret position.

Hussein
  • 42,480
  • 25
  • 113
  • 143
mpen
  • 272,448
  • 266
  • 850
  • 1,236

2 Answers2

10

The following script will hold the caret position and then a button click will insert text at the stored position:

Javascript:

<script type="text/javascript">
//Gets the position of the cursor
function getCaret(el) { 
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
        rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    return rc.text.length; 
  }  
  return 0; 
}

function InsertText() {
    var textarea = document.getElementById('txtArea');
    var currentPos = getCaret(textarea);
    var strLeft = textarea.value.substring(0,currentPos);
    var strMiddle = "-- Hello World --";
    var strRight = textarea.value.substring(currentPos,textarea.value.length);
    textarea.value = strLeft + strMiddle + strRight;
}
</script>

HTML:

<textarea id="txtArea" >Lorem ipsum dolor sit amet, consectetur adipiscing elit.</textarea>
<button onclick="InsertText();">Insert Text</button>

The script can be modified if you want to hold the caret position in a variable onblur.

NakedBrunch
  • 48,713
  • 13
  • 73
  • 98
  • 1
    took me awhile to get it working, but it does seem to workin FF and IE http://jsfiddle.net/EDWw8/ – mpen Mar 01 '11 at 06:12
  • Works in Chrome9 and IE9 too. Good job. Since you haven't accepted the answer, is there something else that you're trying to do? – NakedBrunch Mar 01 '11 at 14:00
  • 1
    Let's not get impatient. Alex's solution is perfectly viable too, and it looks to be more robust. I'll accept an answer once I implement it and decide which one actually works better for me. – mpen Mar 01 '11 at 16:31
  • This was a big help. I needed to patch a problem in Rangyinputs where IE9 wasn't picking up the cursor position. Now I need to figure out how to submit a patch to them. – metric152 Jan 06 '12 at 22:46
  • 1
    this answer still hasn't been accepted. it's been two years. what gives? – Shanimal Nov 16 '13 at 03:18
  • if el.selectionStart === 0, which entirely valid, this code will fail – BenG Oct 07 '15 at 21:38
4

Use the following 2 functions to save and restore text selection.

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

Check Working example at http://jsfiddle.net/LhQda/

Type something in the TEXTAREA, then click outside the TEXTAERA to lose the selection, then click on the focus button to restore selection and focus again.

Hussein
  • 42,480
  • 25
  • 113
  • 143
  • 1
    You realize your code does absolutely nothing, and doesn't work in IE right? `saveSelection` *returns* the selection, which you haven't stored in a variable or anything, and `restoreSelection` takes a `range` as a parameter into which you have passed nothing. Your example works in FF because FF doesn't lose the caret position by default. IE (and perhaps other browsers) do. – mpen Mar 01 '11 at 02:57
  • I didn't realize that. In your question you stated you wanted to `get selected text/caret position of an input that doesn't have focus?`. The code gives you both focus and selected text. – Hussein Mar 01 '11 at 05:55
  • i don't really want/need to focus the element, that's easy to do, i just need the positions, which are also easy to get. the problem is when the element is out of focus, the positions are not retrievable in some browsers. i think though, that simply focusing the field *before* trying to get the positions might fix the problem, but i don't know if that's a reliable fix. I don't see how your `window.getSelection` would be useful if there are multiple inputs on the page, assuming it grabs what...the last selected text? – mpen Mar 01 '11 at 06:18