Set Cursor Position on Contenteditable ≪Div≫

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 a content editable element

Try this:

Just replace range.setStart(el, 2) with range.setStart(el.childNodes[0], 2)

var el = document.getElementsByTagName('div')[0];var range = document.createRange();var sel = window.getSelection();range.setStart(el.childNodes[0], 2);range.collapse(true);sel.removeAllRanges();sel.addRange(range);el.focus();
<div contenteditable>Hi ! How are you doing ?</div>

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!

Set the selector cursor to a new position in contenteditable div

<div> elements have no value property

$("#buttonbold").click(function(){
content.focus();
var valuelength = content.textContent.length - 4;
content.setSelectionRange(content.textContent.length,valuelength);
});

.


<div> elements do not have a setSelectionRange method either,
so here is a solution to make this kind of selection for elements using the contenteditable property:

const myDiv         = document.getElementById('my-div')  ,   btSelectRange = document.getElementById('bt-select-range')  ;function setSelectionRangeCE(el, pos, len)  {   el.focus();  let range = document.createRange()    , sel   = window.getSelection()    ;  range.setStart(el.firstChild, pos)  range.setEnd(el.firstChild, pos+len)  sel.removeAllRanges()  sel.addRange(range)  }btSelectRange.onclick=_=>  {  setSelectionRangeCE(myDiv,2,5)  }
#my-div {  margin:  1em;  padding: .7em;  width:   16em;  height:  3em;  border:  1px solid grey;  }button {  margin:  1em;  }
<div id="my-div" contenteditable >hello world</div>
<button id="bt-select-range" > select range pos:2 len:5 </button>

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 add cursor position after adding a component to content-editable div

So, the problem was I have applied a "display:flex" property to the parent div and now display: "inline-block" helped and its done. Now just applying focus to the main div, I get the the cursor position after the component added.

Set cursor position in content-editable div

Here's a much simpler approach. There are a few things to note:

  • keypress is the only key event in which you can reliably detect which character has been typed. keyup and keydown won't do.
  • The code handles the insertion of parentheses/braces manually by preventing the default action of the keypress event.
  • The selection/caret stuff is simple when using DOM methods.
  • This won't work in IE <= 8, which have different range and selection APIs. If you need support for those browsers, I'd suggest using my own Rangy library. It is possible without it but I really don't want to write the extra code.

Demo:

http://jsfiddle.net/HPeb2/

Code:

var editableEl = document.getElementById("editable");
editableEl.addEventListener("keypress", function(e) {
var charTyped = String.fromCharCode(e.which);
if (charTyped == "{" || charTyped == "(") {
// Handle this case ourselves
e.preventDefault();

var sel = window.getSelection();
if (sel.rangeCount > 0) {
// First, delete the existing selection
var range = sel.getRangeAt(0);
range.deleteContents();

// Insert a text node at the caret containing the braces/parens
var text = (charTyped == "{") ? "{}" : "()";
var textNode = document.createTextNode(text);
range.insertNode(textNode);

// Move the selection to the middle of the inserted text node
range.setStart(textNode, 1);
range.setEnd(textNode, 1);
sel.removeAllRanges();
sel.addRange(range);
}
}
}, false);

Cursor moves to end of the contenteditable div when character removed from div

Analysis

Think of a simple text editor(notepad) where you have typed three characters - TRY

Now, its obvious that the cursor can be placed only at 4 places here, which are:

  • before T
  • between T and R
  • between R and Y
  • after Y

The reason for which is simply because, these 3 characters are the only editable ones here and they are 3 individual entities, which can't be edited/separated further. For example, we can't place the cursor in between the letter 'T' and separate the and from it.

Same is the case with your scenario as the cursor is moved to the end of the div once the   is cleared because the contenteditable=true is set to the <div> and is set as false to the <span>. Therefore the div is the only editable element here and the span is not. So the cursor can position itself only on an editable place which is either at the beginning of an editable element(div in this case) or at the end of it and not in between.

As the div is a block element, the cursor is moved to the end of the page as the block elements occupy the whole width of its parent. We can see the cursor being moved to the middle of the page if we set width: 50%; to the div.

Solution

Considering your comments on other answers, that you need to keep the width as 100%, the solution is to wrap the div with another one which also have the attribute contenteditable=true and keep the child div as an inline-block element.

<div contenteditable=true>
<div class="inl-blck" contenteditable=true><span contenteditable='false'>UserName</span> </div>
</div>

CODEPEN

Explanation

Here, both the parent and child divs are editable where the parent occupying the full width (100%) and the child is an inline-block element, which just occupies the space of its contents. Therefore, once the   is cleared, the cursor moves to the end of the next editable content which is the child div.

Note that, you need to keep the child div and span along with the   in the same line in you code as otherwise it will create extra characters (whitespaces) in the section, which will break the contenteditable further.

Hope this helps.



Related Topics



Leave a reply



Submit