2

I insert a <ul><li></li><ul> into a content editable div, and would like to move the caret into the li.

I attempted to use jQuery focus on the li, but focus doesn't work on li. I then attempted to add a tabindex attribute to li, but focus highlighted the area without actually moving the caret into the li.

Any help would be appreciated, thank you!

eyphka
  • 75
  • 6
  • Not positive but fairly sure you need an input field to get the carrot, you can still have focus with a normal element (which is what I suspect is happening) but the carrot is part of it being an input. Why exactly do you want the carrot there? – Blue Nov 08 '14 at 07:00

1 Answers1

1

If an element can contain the caret, you can move the caret to that element using:

$([selector]).focus();
$([selector]).select(); //include this line if '.focus()' alone isn't working

Although I don't think the li element can contain the caret, but it's inside an editable div as you say, so maybe then it can. Couldn't say for sure without knowing the exacts of your situation.


... After trying really hard for a really long time with the fiddle from the first comment, I'm really starting to believe that it's just not possible. I eventually got to this, but aren't getting any further.
(Original caret positioning code by Tim Down.)


UPDATE

After even longer and ever harder trying (by the OP, I had given up), finally a solution was found.
Yes, it's pretty hacky, and not IE9- compatible, but it does the job:

$(window).on('load',function(){
  $('#addListBtn').click(function(){
    $('div.input').append('<ul><li><div id="insertedList">&nbsp;</div></li></ul>');
    if (setCaret('insertedList')) {$('#insertedList').remove();} //don't remove until setCaret() has fully executed
  });

  function setCaret(id) {
    var range = document.createRange();
    range.setStart(document.getElementById(id).childNodes[0],0);
    range.collapse(true);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
    return true;
  }
});
.input {border: 1px solid #ccc;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<button id="addListBtn">Insert List</button><br /><br /> <!--FOR TESTING ONLY!-->

<div class="input" contenteditable="true">
  Some text that's already in the div.
</div>
(fiddle: http://jsfiddle.net/nsf0rt51/10/)
  • This code first appends the list: <ul><li><div id="insertedList"></div></li></ul>. Notice the dummy div inside the li.
    (This is done, because in order to set the caret, the element must have an ID and must have some content. By using a dummy div, we can just remove that div afterwards when the caret is set, and what remains is a clean list.)
  • Next, the caret is set to the start of the dummy div. I put the code for this inside a standard function that is invoked from inside the click-handler. I did it this way, so that the function can be invoked from multiple places (maybe you want to insert other things that also need focus upon insertion).
  • Finally, the dummy div is removed from the DOM, leaving us with a clean <ul><li></li></ul>, with the caret blinking inside it.

Notice that $([selector]).focus(); isn't necessary anymore, because the focusing is happening automatically when the caret is set.
If you find that the code isn't working however, try and put $('div.input').focus(); right after the append line, maybe it will help.

Community
  • 1
  • 1
myfunkyside
  • 3,890
  • 1
  • 17
  • 32
  • I made this into a jsfiddle (scraped this together in a hurry, so let me know if you meant something else) but your solution doesn't seem to work. http://jsfiddle.net/weirderthan/nsf0rt51/ – eyphka Nov 08 '14 at 17:52
  • I updated my answer (below the horizontal line) ...don't get your hopes up:( – myfunkyside Nov 08 '14 at 21:42
  • It is possible, it is quite difficult to get the right position AND make it work in Internet Explorer and Firefox (and Chrome, and Safari). Each browser has its own little quirks when it comes to handling ranges. – Alexis Wilke Nov 08 '14 at 21:46
  • I got it to work, with some help from the code you supplied... Here is this insanely hacky solution... http://jsfiddle.net/weirderthan/nsf0rt51/7/ Essentially I add a div to the li, set the selection to in that, and then remove the div. – eyphka Nov 09 '14 at 01:11
  • Heheh, no. Sadly, no. I had thought about this too, although I would have chosen a `` instead of a div. But I decided it would be too messy, because I assume people are also able to just type directly in that div. And what you get then, is that only the `li`'s that have been added using javascript wil have those divs or spans inside them, and the li's that were added by typing them directly will not have them. – myfunkyside Nov 09 '14 at 01:14
  • Okay your last comment could work. Yep, you gone on and did it:) Nice, that would actually be the most adequate solution, very sharp thinking – myfunkyside Nov 09 '14 at 01:14
  • Awesome, if you update your answer with this janky, not optimized for all browser solution, I'll go ahead and accept. – eyphka Nov 09 '14 at 01:24
  • Yeah, I'll revise my answer and put it in there for everyone to see. Quick question: do you only want to insert the whole `
      • ` at once, or do you also need to insert individual `li`'s after the `ul` is already there?
    – myfunkyside Nov 09 '14 at 01:25
  • The whole `
    `.
    – eyphka Nov 09 '14 at 01:30
  • The answer is updated, I was trying to optimize it, hoping I could get it to work with just `.focus()` after all, because now there's that inner `div` - since that also worked when I changed `$('li').focus();` to `$('div').focus();` in [your first fiddle](http://jsfiddle.net/nsf0rt51/1/). But sadly that doesn't seem to work unless the div is the outermost element, so all that `range` and `selection` stuff is really necessary. – myfunkyside Nov 09 '14 at 03:37