FishBasketGordo
FishBasketGordo

Reputation: 23142

Why doesn't IE's caret position in a text input equal the string index? What's the workaround?

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 <input> or <textarea>. Whereas Chrome and Firefox report the caret position analogously to the index within the string value, IE8 does not.

First off, here are the functions that I use to retrieve the caret positions respectively in Chrome/Firefox and IE:

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

As far as I can tell, the functions I've implemented are fairly standard. Now, say I have a <textarea>, 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:

--------------------------------------------------------------------
| 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)                       |
--------------------------------------------------------------------

In IE8, the results are unfortunately very different:

--------------------------------------------------------------------
| 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?)    |
--------------------------------------------------------------------

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?

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.

Here is a working example: http://jsfiddle.net/FishBasketGordo/ExZM9/

EDIT: @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:

function getCaretPosIE(txtbox) {
    var caret, normalizedValue, range, textInputRange, len, endRange;    
    txtbox.focus();
    range = document.selection.createRange();    
    if (range && 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) > -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;
        }
    }
}

Here is the corrected, working example: http://jsfiddle.net/FishBasketGordo/uXWXF/

Upvotes: 1

Views: 3195

Answers (1)

Tim Down
Tim Down

Reputation: 324607

Getting the caret position relative the value property of the textarea is not simple in IE because of the line break issues you've come across. I spent some time a while ago researching it and came up with what I think is the best approach out there. I've posted it a few times on Stack Overflow. Here's one example:

IE's document.selection.createRange doesn't include leading or trailing blank lines

Upvotes: 2

Related Questions