How to set carriage / cursor position in contenteditable div between two divs.

Consider the following contenteditable div.

<div contenteditable="true"> <div>bold text</div><div>bold text</div> </div> 

If I place the cursor between two divs and start typing, it appears in bold instead of inserting new node text between the two divs. The same thing happens if you get home and try to enter something before the first div. It becomes part of the first div.

If I check the startContainer of the range returned from the selection, I get the content for one of the div instead of the empty node text, as expected.

See http://jsfiddle.net/9ZZpX/3/

The question is, why is this happening? How can I choose a place between divs so that when I enter something it is not highlighted in bold? (Obviously, I can add a space, and this works around the problem, but it's pretty ugly.)

You can see how this works properly on Facebook if you type @mention in the status update field and press HOME. If you type, it will not be highlighted.

The only thing I could think of was to intercept the keystroke and insert the node text programmatically, but it seems ugly.

I searched like crazy and cannot find any links confirming how this should really work. Obviously, something that I do not understand, and the documentation in this area is really not enough.

(What I want to do also detects when the cursor is about to enter one of these divs and jump over it. If the two divs are next to each other, the cursor jumps to one of the divs and it twists the work.)

Further information on what I'm trying to do: http://a-software-guy.com/2012/12/the-horrors-of-cursor-positioning-in-contenteditable-divs/

+6
javascript dom range cursor contenteditable
source share
3 answers

Browsers do not agree with this. Firefox will allow you to position the carriage in more positions than most browsers, but WebKit and IE have a certain idea of ​​the actual carriage positions and will change the range that you add for selection to match the closest current position. This makes sense: having different document positions and therefore behavior for the same visual carriage location is misleading to the user. However, this is due to the rigidity for the developer.

This is not documented anywhere. the current selection specification says nothing about this, mainly because the specifications did not exist when browsers implemented their selection APIs, and there is no single behavior for the current specification for the document.

One option is to intercept the keypress event, as you suggest, although this does not help when the user inserts content into the context menu or the context menu. Another would be to track the selection with mouse events and key events, create elements with, say, a zero-width mileage symbol to place the carriage, and place the carriage in one of these elements when necessary. As you say, ugly.

+7
source share

My answer will be just a complement to Tim, which is comprehensive.

AFAIK Facebook does not use editable content. The status bar is made of a simple text area and a div layer below it, on which they display blue rectangles for nicknames.

Although, even if they did, it would be a different matter, because the nickname would be an inline element, and, fortunately, the situation with inline elements is simpler :).

As for carriage positioning in inaccessible places - at CKEditor we had the same problem. There are many places where the user cannot move the carriage. We decided to solve this problem using a plugin called Magic-line . As you can see in the demo, we completely circumvented the selection problem, and I think this is the best way to solve this problem. It is very useful, and in CKEditor 4.0.1 it will (and is already on the wizard ), also fully accessible by keystroke.

+4
source share

Another thing you can do is use the Mutation Observer to catch mutations, and then fix them after this fact. In my use case, I was lucky that each element had a predefined text. When a mutational observer appears, I simply moved the changed text to the new text node before or after the element, if necessary. This seems a lot simpler than other parameters, because the observer launches all changes in the character data, and also has a proper record of all changes, unlike the case of a keystroke.

0
source share