6

Consider the following contenteditable div.

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

If I position the cursor between the two divs and start typing the text comes out bold instead of inserting a new text node between the two divs. The same happens if you hit home and try to type something in front of the first div. It becomes part of the first div.

If I inspect the startContainer of the range that's returned from the selection, I get the content for one of the div's instead of an empty text node as I would expect.

$( '#EDITABLE' ).focus();

var selection = window.getSelection();

var range = document.createRange();

var div = $('#div2').get(0);

range.setStartBefore(div);
range.collapse(true);

selection.removeAllRanges();
selection.addRange(range);

// cursor should now be between div1 and div2

range = window.getSelection().getRangeAt(0);

console.log("range object returned is: ", range);

// type something into the content editable div. why is it coming
// up bold since the cursor should be between the divs? it's 
// positioning the cursor at the end of the previous div. I want to
// target the spot between the divs. how?
div.content {
  display: inline-block;
  font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div contenteditable="true" id="EDITABLE">
  <div class="content" id="div1">Content for div1</div>
  <div class="content" id="div2">content for div 2</div>
</div>

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

The question is why does this happen? How can I select the spot between the divs so that when I type something it does not bold? (Obviously I can add a space and that works around the problem but that's quite ugly.)

You can see this working correctly at Facebook if you enter an @mention in a status update box and press HOME. If you type the text will not get highlighted.

The only thing I've been able to think of is intercepting the keypress and inserting a text node programmatically but that seems ugly.

I searched like crazy and can't find any references that document how this is really supposed to work. There is obviously something that I do not understand and the documentation is really lacking in this area.

(What I want to be able to do as well is detect when the cursor is about to enter one of these divs and jump over it. If the two divs are right next to each other, the cursor jumps into one of the divs and it mucks up the works.)

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

4

3 に答える 3

8

ブラウザはこれに一貫性がありません。Firefox では、ほとんどのブラウザーよりも多くの位置にキャレットを配置できますが、WebKit と IE は両方とも、有効なキャレット位置について明確なアイデアを持っており、選択範囲に追加した範囲を修正して、最も近い有効な位置に適合させます。これは理にかなっています。ドキュメントの位置が異なるため、同じビジュアル キャレットの場所に対する動作がユーザーを混乱させます。ただし、これには開発者の柔軟性の欠如という代償が伴います。

これはどこにも文書化されていません。現在の選択の仕様は、それについて何も述べていません。主な理由は、ブラウザーが選択 API を実装したときに仕様が存在せず、現在の仕様が文書化する統一された動作がないためです。

1 つのオプションは、提案したようにイベントをインターセプトするkeypressことですが、これは、ユーザーが編集またはコンテキスト メニューを使用してコンテンツに貼り付けた場合には役に立ちません。もう 1 つは、マウス イベントとキー イベントを使用して選択を追跡し、たとえば、キャレットを配置するゼロ幅のスペース文字を含む要素を作成し、必要に応じてそれらの要素の 1 つにキャレットを配置することです。おっしゃるとおり、醜いです。

于 2012-12-31T17:02:28.850 に答える
4

私の答えは、包括的なティムの答えへの単なる追加になります。

私の知る限り、Facebookは編集可能なコンテンツを使用していません。ステータス ボックスは、単純な textarea とその下の div レイヤーで構成されており、ニックネームの青い四角形がレンダリングされます。

ただし、たとえそうであったとしても、それは別のケースになります.nickはインライン要素であり、幸いなことにインライン要素を使用すると状況はより単純になるためです:)。

アクセスできない場所にキャレットを配置することについて-CKEditorでも同じ問題がありました。ユーザーがキャレットを移動できない場所がたくさんあります。この問題をMagic-lineというプラグインで解決することにしました。デモでわかるように、選択の問題を完全に回避しました。これがこの問題を解決する最善の方法だと思います。これは非常に使いやすく、CKEditor 4.0.1 ではキーストロークで完全にアクセスできるようになります (そしてすでにmasterにあります)。

于 2013-01-01T16:02:06.210 に答える