title: Why doesn't IE's caret position in a text input equal the string index? What's the workaround?
body: <p>I'm not surprised, but I've discovered that IE8 behaves very differently than Chrome and Firefox with respect to retrieving the caret position from a text <code>&lt;input&gt;</code> or <code>&lt;textarea&gt;</code>. Whereas Chrome and Firefox report the caret position analogously to the index within the string value, IE8 does not.</p>
  
  <p>First off, here are the functions that I use to retrieve the caret positions respectively in Chrome/Firefox and IE:</p>
  
  <pre><code>function getCaretPosGecko(txtbox) {
      return txtbox.selectionStart;
  }
  
  function getCaretPosIE(txtbox) {
      var range, rangeCopy;    
      txtbox.focus();
      range = document.selection.createRange();    
      if (range !== null) {
          rangeCopy = range.duplicate();
          rangeCopy.moveToElementText(txtbox);
          rangeCopy.setEndPoint('EndToStart', range);    
          return rangeCopy.text.length - range.text.length;
      } else {
          return -1;
      }
  }
  </code></pre>
  
  <p>As far as I can tell, the functions I've implemented are fairly standard. Now, say I have a <code>&lt;textarea&gt;</code>, and I type an "a" on the first line, a "b" on the second line, and nothing else. The code above reports the following caret positions for the given criteria in Chrome and Firefox:</p>
  
  <pre><code>--------------------------------------------------------------------
  | I put the caret...       | Code reports caret at position...     |
  --------------------------------------------------------------------
  | 1st line, after the "a"  | 1 (As expected)                       |
  | 2nd line, before the "b" | 2 (As expected)                       |
  | 2nd line, after the "b"  | 3 (As expected)                       |
  --------------------------------------------------------------------
  </code></pre>
  
  <p>In IE8, the results are unfortunately very different:</p>
  
  <pre><code>--------------------------------------------------------------------
  | I put the caret...       | Code reports caret at position...     |
  --------------------------------------------------------------------
  | 1st line, after the "a"  | 1 (As expected)                       |
  | 2nd line, before the "b" | 1 (Maybe it doesn't count new lines?) |
  | 2nd line, after the "b"  | 4 (Now, it seems to include \r\n?)    |
  --------------------------------------------------------------------
  </code></pre>
  
  <p>I'm assuming that IE is including a "\r\n" in the calculation for the third case, but why doesn't it include it for the second case? </p>
  
  <p><strong>More importantly, what can I do to work around this discrepancy? I need to know where the caret is within the string value of the textbox to do some string manipulations. My first thought was to offset the caret position in IE by the number of "\r\n" before the caret, but this won't work if the caret is at the beginning or end of a line.</strong></p>
  
  <p>Here is a working example: <a href="http://jsfiddle.net/FishBasketGordo/ExZM9/" rel="nofollow">http://jsfiddle.net/FishBasketGordo/ExZM9/</a></p>
  
  <p><strong>EDIT:</strong> @Tim Down's answer below was just about spot on. I did need to make a few modifications. The function below returns the exact same results as its Gecko analog:</p>
  
  <pre><code>function getCaretPosIE(txtbox) {
      var caret, normalizedValue, range, textInputRange, len, endRange;    
      txtbox.focus();
      range = document.selection.createRange();    
      if (range &amp;&amp; range.parentElement() == txtbox) {
          len = txtbox.value.length;
          normalizedValue = txtbox.value.replace(/\r\n/g, '');
          textInputRange = txtbox.createTextRange();
          textInputRange.moveToBookmark(range.getBookmark());
          endRange = txtbox.createTextRange();
          endRange.collapse(false);
          if (textInputRange.compareEndPoints("StartToEnd", endRange) &gt; -1) {
              caret = txtbox.value.replace(/\r\n/g, '\n').length;
          } else {
              caret = -textInputRange.moveStart("character", -len);
              caret += normalizedValue.slice(0, start).split("\n").length - 1;
          }
      }
  }
  </code></pre>
  
  <p>Here is the corrected, working example: <a href="http://jsfiddle.net/FishBasketGordo/uXWXF/" rel="nofollow">http://jsfiddle.net/FishBasketGordo/uXWXF/</a></p>