How do you get the caret position in a using JavaScript?
For example: This is| a text
This should return 7
Updated 5 September 2010
Seeing as everyone seems to get directed here for this issue, I'm adding my answer to a similar question, which contains the same code as this answer but with full background for those who are interested:
IE's document.selection.createRange doesn't include leading or trailing blank lines
To account for trailing line breaks is tricky in IE, and I haven't seen any solution that does this correctly, including any other answers to this question. It is possible, however, using the following function, which will return you the start and end of the selection (which are the same in the case of a caret) within a <textarea>
or text <input>
.
Note that the textarea must have focus for this function to work properly in IE. If in doubt, call the textarea's focus()
method first.
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
I modified the above function to account for carriage returns in IE. It's untested but I did something similar with it in my code so it should be workable.
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);
var add_newlines = 0;
for (var i=0; i<rc.text.length; i++) {
if (rc.text.substr(i, 2) == '\r\n') {
add_newlines += 2;
i++;
}
}
//return rc.text.length + add_newlines;
//We need to substract the no. of lines
return rc.text.length - add_newlines;
}
return 0;
}
With Firefox, Safari (and other Gecko based browsers) you can easily use textarea.selectionStart, but for IE that doesn't work, so you will have to do something like this:
function getCaret(node) {
if (node.selectionStart) {
return node.selectionStart;
} else if (!document.selection) {
return 0;
}
var c = "\001",
sel = document.selection.createRange(),
dul = sel.duplicate(),
len = 0;
dul.moveToElementText(node);
sel.text = c;
len = dul.text.indexOf(c);
sel.moveStart('character',-1);
sel.text = "";
return len;
}
(complete code here)
I also recommend you to check the jQuery FieldSelection Plugin, it allows you to do that and much more...
Edit: I actually re-implemented the above code:
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;
}
Check an example here.
If you don't have to support IE, you can use selectionStart
and selectionEnd
attributes of textarea
.
To get caret position just use selectionStart
:
function getCaretPosition(textarea) {
return textarea.selectionStart
}
To get the strings surrounding the selection, use following code:
function getSurroundingSelection(textarea) {
return [textarea.value.substring(0, textarea.selectionStart)
,textarea.value.substring(textarea.selectionStart, textarea.selectionEnd)
,textarea.value.substring(textarea.selectionEnd, textarea.value.length)]
}
Demo on JSFiddle.
See also HTMLTextAreaElement docs.