36

The old version of the question is below, after researching more, I decided to rephrase the question. The problem as before is, I need to focus a contenteditable div without highlighting the text, doing straight up focus highlights the text in Chrome.

I realize that people solved this problems in textareas by resetting the caret position in the textarea. How can I do that with a contenteditable element? All the plugins I've tried only works with textareas. Thanks.

Old Phrasing of the question:

I have a contenteditable element that I want to focus, but only insofar as to place the cursor at the front of the element, rather selecting everything.

elem.trigger('focus'); with jquery selects all the text in the entire element in chrome. Firefox behaves correctly, setting the caret at the front of the text. How can I get Chrome to behave the way I want, or is focus perhaps not what I'm looking for.

Thanks all.

Luca Filosofi
  • 30,905
  • 9
  • 70
  • 77
Mark
  • 32,293
  • 33
  • 107
  • 137
  • This [previous question](http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area) may help with cursor positioning. – Ken Redler May 20 '10 at 04:56
  • Are you sure those work on contenteditable. I was not able to get those to work. – Mark May 20 '10 at 05:15
  • @Mark: i have updated the code to latest jquery and modified the demo to work with rich content. – Luca Filosofi Apr 15 '14 at 09:59

6 Answers6

30

Maybe I'm misreading the question, but wouldn't the following do (assuming an editable <div> with id "editable")? The timer is there because in Chrome, the native browser behaviour that selects the whole element seems to trigger after the focus event, thereby overriding the effect of the selection code unless postponed until after the focus event:

var div = document.getElementById("editable");

div.onfocus = function() {
    window.setTimeout(function() {
        var sel, range;
        if (window.getSelection && document.createRange) {
            range = document.createRange();
            range.selectNodeContents(div);
            range.collapse(true);
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (document.body.createTextRange) {
            range = document.body.createTextRange();
            range.moveToElementText(div);
            range.collapse(true);
            range.select();
        }
    }, 1);
};

div.focus();
Tim Down
  • 318,141
  • 75
  • 454
  • 536
20

demo: http://so.lucafilosofi.com/jquery-setting-cursor-position-in-contenteditable-div/

      <div id="editable" contentEditable="true">
            <h2>Lorem</h2> <p>ipsum dolor <i>sit</i> 
               amet, consectetur <strong>adipiscing</strong> elit.</p> Aenean.
        </div>

    <script type="text/javascript">
        $(function () {
            $('[contentEditable="true"]').on('click', function (e) {
                if (!$(this).hasClass('editing')) {
                    var html = $(this).html();
                    if (html.length) {
                        var range = rangy.createRange();
                        $(this).toggleClass('editing').html('<span class="content-editable-wrapper">' + html + '</span>');
                        var $last = $(this).find('.content-editable-wrapper');
                        range.setStartAfter($last[0]);
                        range.collapse(false);
                        rangy.getSelection().setSingleRange(range);
                    }
                }
            }).on('blur', function () {
                $(this).toggleClass('editing').find('.content-editable-wrapper').children().last().unwrap();
            });
        });
    </script>
Luca Filosofi
  • 30,905
  • 9
  • 70
  • 77
  • 1
    That's an interesting hack, great idea actually. Thank you. But the contenteditable is a wysiwyg editor, so I can't just substitute a textfield. – Mark May 28 '10 at 06:20
  • 1
    An interesting idea, and valuable for some I'm sure, but this does not answer the question of how to set the carat position on a contenteditable div. Adding a "fake" input box is not really a solution; if I wanted to use an input, I would have used an input. – Zane Claes Dec 24 '12 at 14:28
  • does not answer the question. better answer at http://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div – jaredjacobs Jan 18 '13 at 23:30
  • i have updated the code to the latest jQuery version and modified the demo to work as expected also with rich content. without adding extra input or textarea. – Luca Filosofi Apr 15 '14 at 10:00
3

Yes it happens because you have used

elem.trigger('focus'); 

try to use class or to identify the element on which you want to fire a trigger event.

Chirag
  • 902
  • 1
  • 9
  • 10
1

I managed to solve that problem after a bit of poking around the DOM.

elm.focus();
window.getSelection().setPosition(0);

It probably only works on WebKit browsers, but since it is the only source of the problem, I added a conditional (using jQuery)

if(!$.browser.webkit) {
    elm.focus();
} else {
    elm.focus();
    window.getSelection().setPosition(0);
}

Hope this solves your problem.

DfKimera
  • 2,076
  • 2
  • 21
  • 39
0

Set pointer position in pre or div tag:

function setCursor(pos) {
    var el = document.getElementById("asd");
    var range = document.createRange();
    var sel = window.getSelection();
    range.setStart(el.childNodes[0], pos);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
    el.focus();
}

$('button').click(function () {
    setCursor(5);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="asd" contenteditable="true" >
asd
two
</div>
<button>Set caret position</button>

Source: https://social.msdn.microsoft.com/Forums/en-US/f91341cb-48b3-424b-9504-f2f569f4860f/getset-caretcursor-position-in-a-contenteditable-div?forum=winappswithhtml5

K. Kuksin
  • 41
  • 9
0

for example for inserting image in cursor position:

var insertImgTag = document.createElement("div");
insertImgTag.id = "insertImgTag";
if (document.getSelection().anchorNode != null) {
    document.getSelection().getRangeAt(0).insertNode(insertImgTag);}

then select created element:

$("#insertImgTag")
            .parent()
            .html(
                "<img src=/images/" + $("#name").val() + " width='" + imgWidth + "%' alt='" + imgAlt + "'>"
            );
reza
  • 11
  • 4