I would argue that counting line breaks as two characters when calculating selection boundaries/cursor position is the correct approach. Fundamentally, those two characters \r\n
are there in the text. They are present in the textarea's value
property and they are in the value that is submitted to the server.
The only arguments I can see for counting line breaks as one character are:
- Consistency with other browsers
- IE's
TextRange
methods consider the line breaks as one character
I think neither is valid. Firstly, IE is already inconsistent with other browsers in counting line breaks as two characters rather than one. Secondly, IE's TextRange
character-based methods are a little insane anyway, causing problems wherever they're used.
I think it makes total sense to consider the selection/caret position as a position relative to the actual text in the textarea. This allows easy manipulation of the text.
Here are two main functions. The first is the only textarea selection/caret position getting function I've seen that works correctly with all line breaks. You can find this here:
How to get the start and end points of selection in text area?. Second, here's a complementary setSelection
function:
function offsetToRangeCharacterMove(el, offset) {
return offset - (el.value.slice(0, offset).split("\r\n").length - 1);
}
function setSelection(el, startOffset, endOffset) {
var range = el.createTextRange();
var startCharMove = offsetToRangeCharacterMove(el, startOffset);
range.collapse(true);
if (startOffset == endOffset) {
range.move("character", startCharMove);
} else {
range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset));
range.moveStart("character", startCharMove);
}
range.select();
}