Get contentEditable caret position
The following code assumes:
- There is always a single text node within the editable
<div>
and no other nodes - The editable div does not have the CSS
white-space
property set topre
If you need a more general approach that will work content with nested elements, try this answer:
https://stackoverflow.com/a/4812022/96100
Code:
function getCaretPosition(editableDiv) { var caretPos = 0, sel, range; if (window.getSelection) { sel = window.getSelection(); if (sel.rangeCount) { range = sel.getRangeAt(0); if (range.commonAncestorContainer.parentNode == editableDiv) { caretPos = range.endOffset; } } } else if (document.selection && document.selection.createRange) { range = document.selection.createRange(); if (range.parentElement() == editableDiv) { var tempEl = document.createElement("span"); editableDiv.insertBefore(tempEl, editableDiv.firstChild); var tempRange = range.duplicate(); tempRange.moveToElementText(tempEl); tempRange.setEndPoint("EndToEnd", range); caretPos = tempRange.text.length; } } return caretPos;}
#caretposition { font-weight: bold;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><div id="contentbox" contenteditable="true">Click me and move cursor with keys or mouse</div><div id="caretposition">0</div><script> var update = function() { $('#caretposition').html(getCaretPosition(this)); }; $('#contentbox').on("mousedown mouseup keydown keyup", update);</script>
Get caret (cursor) position in contentEditable area containing HTML content
UPDATE
I've written a simpler version of this that also works in IE < 9:
https://stackoverflow.com/a/4812022/96100
Old Answer
This is actually a more useful result than a character offset within the text of the whole document: the startOffset
property of a DOM Range (which is what window.getSelection().getRangeAt()
returns) is an offset relative to its startContainer
property (which isn't necessarily always a text node, by the way). However, if you really want a character offset, here's a function that will do it.
Here's a live example: http://jsfiddle.net/timdown/2YcaX/
Here's the function:
function getCharacterOffsetWithin(range, node) {
var treeWalker = document.createTreeWalker(
node,
NodeFilter.SHOW_TEXT,
function(node) {
var nodeRange = document.createRange();
nodeRange.selectNode(node);
return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
},
false
);
var charCount = 0;
while (treeWalker.nextNode()) {
charCount += treeWalker.currentNode.length;
}
if (range.startContainer.nodeType == 3) {
charCount += range.startOffset;
}
return charCount;
}
get cursor position in contenteditable div with html-tags
This gives you what you want. It will give you the length of the html also.
https://jsfiddle.net/ko5Lhbeo/
Change this:
$('.msg').on('keyup',function(e){
$('.cursor').html(getCaretPosition(document.getElementById('msg')));
})
to this:
// Added DOMSubtreeModified event here to fire whenever any modifications to the sub tree
$('.msg').on('keyup DOMSubtreeModified',function(e) {
$('.cursor').html($('#msg').html().length);
})
Get and set cursor position with contenteditable div
A good rich-text editor is one of the harder things to do currently, and is pretty much a project by itself (unfriendly API, huge number of corner cases, cross-browser differences, the list goes on). I would strongly advise you to try and find an existing solution.
Some libraries that can be used include:
- Quill (http://quilljs.com)
- WYSGIHTML (http://wysihtml.com)
- CodeMirror library (http://codemirror.net)
How to set the caret (cursor) position in a contenteditable element (div)?
In most browsers, you need the Range
and Selection
objects. You specify each of the selection boundaries as a node and an offset within that node. For example, to set the caret to the fifth character of the second line of text, you'd do the following:
function setCaret() {
var el = document.getElementById("editable")
var range = document.createRange()
var sel = window.getSelection()
range.setStart(el.childNodes[2], 5)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
<div id="editable" contenteditable="true">
text text text<br>text text text<br>text text text<br>
</div>
<button id="button" onclick="setCaret()">focus</button>
Set Caret Position in 'contenteditable' div that has children
So, I was experiencing the same issue and decided to write my own routine quickly, it walks through all the child nodes recursively and set the position.
Note how this takes a DOM node as argument, not a jquery object as your original post does
// Move caret to a specific point in a DOM element
function SetCaretPosition(el, pos){
// Loop through all child nodes
for(var node of el.childNodes){
if(node.nodeType == 3){ // we have a text node
if(node.length >= pos){
// finally add our range
var range = document.createRange(),
sel = window.getSelection();
range.setStart(node,pos);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
return -1; // we are done
}else{
pos -= node.length;
}
}else{
pos = SetCaretPosition(node,pos);
if(pos == -1){
return -1; // no need to finish the for loop
}
}
}
return pos; // needed because of recursion stuff
}
I hope this'll help you!
Related Topics
What Advantages Does Using (Function(Window, Document, Undefined) { ... })(Window, Document) Confer
Why Does Settimeout() "Break" for Large Millisecond Delay Values
Unexpected JavaScript Date Behavior
Save a Pre Element as PDF with CSS
How to Use JSON Data to Populate the Options of a Select Box
Is It Ok to Add Your Own Attributes to HTML Elements
JavaScript Loading Progress of an Image
Clearing My Form Inputs After Submission
How to Extend a Class Without Having to Use Super in Es6
JavaScript Sort Function. Sort by First Then by Second
Closure in JavaScript - Whats Wrong
How to Stop Event Bubbling on Checkbox Click
How to Reorder Divs Using Flex Box
Using Queryselectorall to Change the Style Property of Multiple Elements