Set Caret to a "contenteditable" div that has children
I have an HTML structure like this:
<div contenteditable="true">This is some plain, boring content.</div> I also have this function, which allows me to set the caret position anywhere I want in the div:
// Move caret to a specific point in a DOM element function SetCaretPosition(object, pos) { // Get key data var el = object.get(0); // Strip inner object from jQuery object var range = document.createRange(); var sel = window.getSelection(); // Set the range of the DOM element range.setStart(el.childNodes[0], pos); range.collapse(true); // Set the selection point sel.removeAllRanges(); sel.addRange(range); } This code works completely fine until I start adding child tags (span, b, i, u, strike, sup, sub) to the div, for example.
<div contenteditable="true"> This is some <span class="fancy">plain</span>, boring content. </div> Things get more complicated when these child tags end with child tags, like
<div contenteditable="true"> This is some <span class="fancy"><i>plain</i></span>, boring content. </div> Essentially, what happens is that setStart throws an IndexSizeError when I try to SetCaretPosition an index higher than the start of the child tag. setStart only works until it reaches the first child tag.
What I need is for the SetCaretPosition function SetCaretPosition process an unknown number of these child tags (and possibly an unknown number of nested child tags), so position preferences work just as if there were no tags.
So for both:
<div contenteditable="true">This is some plain, boring content.</div> and this:
<div contenteditable="true"> This is <u>some</u> <span class="fancy"><i>plain</i></span>, boring content. </div> SetCaretPosition(div, 20); puts the carriage in front of "b" in the "bore".
What code do i need? Thank you very much!
So, I faced the same problem and decided to quickly write my own procedure, it recursively iterates over all the child nodes and sets the position. Note how this takes a DOM node as an argument, not a jquery object, as your original message 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 } Hope this helps you!
It works only for the Text childNodes (0) object . So you have to do it. This is not a very standard code, but it works. Naked is that (p) id (we) will output the text of the object. If so, then this might work.
<div id="editable" contenteditable="true">dddddddddddddddddddddddddddd<p>dd</p>psss<p>dd</p><p>dd</p> <p>text text text</p> </div> <p id='we'></p> <button onclick="set_mouse()">focus</button> <script> function set_mouse() { var as = document.getElementById("editable"); el=as.childNodes[1].childNodes[0];//goal is to get ('we') id to write (object Text) var range = document.createRange(); var sel = window.getSelection(); range.setStart(el, 1); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); document.getElementById("we").innerHTML=el;// see out put of we id } </script>