18

典型的な wysiwyg エディター html (太字、アンカー、リスト) を含む contenteditable div があります。

現在のカーソルが onKeyDown で、div の最初と最後にあるかどうかを判断する必要があります。この理由は、カーソルの位置と押されたキーに基づいて、この div をバックスペースの前の div とマージするか、Enter で新しい次の div を作成したい場合があるためです。

範囲をいじってきましたが、要素内で html を操作していると、かなり複雑になります。

簡単な解決策を見落としているに違いないと思っています。

これを判断する比較的簡単な方法はありますか - 私は Rangy のようなライブラリを使用することにオープンです。

ありがとう!

編集:私はこれらの行に沿って何かを考えています:

$('.mycontenteditable').bind('keydown', handle_keydown)

handle_keydown = function(e) {

  range = window.getSelection().getRangeAt(0)
  start_range = document.createRange()
  start_range.selectNodeContents(this.firstChild)
  start_range.collapse(true) // collapse to start
  is_start = start_range.compareBoundaryPoints(Range.START_TO_START,range)
  end_range = document.createRange()
  end_range.selectNodeContents(this.lastChild)
  end_range.collapse(false)
  is_end = end_range.compareBoundaryPoints(Range.END_TO_END,range)
}

このようなもので奇妙な問題に遭遇するでしょうか?

4

5 に答える 5

25

不必要なクローン作成を避けるのではなく、オブジェクトのtoString()メソッドを使用することを除いて、私はあなたと同様のアプローチを使用します。また、IE < 9 (範囲をサポートしていません) では、 のプロパティで同様のアプローチを使用できます。RangecloneContents()textTextRange

toString()範囲のメソッドはノードのプロパティと同じように機能し、テキストノードのみを考慮し、またはブロックtextContentによって暗示される改行を考慮しないため、コンテンツに先頭および/または末尾の改行がある場合、これには問題があることに注意してください。<br>要素。また、CSS は考慮されません。たとえば、非表示になっている要素内のテキストdisplay: noneが含まれます。

次に例を示します。

ライブデモ: http://jsfiddle.net/YA3Pu/1/

コード:

function getSelectionTextInfo(el) {
    var atStart = false, atEnd = false;
    var selRange, testRange;
    if (window.getSelection) {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            selRange = sel.getRangeAt(0);
            testRange = selRange.cloneRange();

            testRange.selectNodeContents(el);
            testRange.setEnd(selRange.startContainer, selRange.startOffset);
            atStart = (testRange.toString() == "");

            testRange.selectNodeContents(el);
            testRange.setStart(selRange.endContainer, selRange.endOffset);
            atEnd = (testRange.toString() == "");
        }
    } else if (document.selection && document.selection.type != "Control") {
        selRange = document.selection.createRange();
        testRange = selRange.duplicate();

        testRange.moveToElementText(el);
        testRange.setEndPoint("EndToStart", selRange);
        atStart = (testRange.text == "");

        testRange.moveToElementText(el);
        testRange.setEndPoint("StartToEnd", selRange);
        atEnd = (testRange.text == "");
    }

    return { atStart: atStart, atEnd: atEnd };
}
于 2011-09-19T23:19:34.843 に答える
15

これが私がこれを解決することになった方法です。上記の提案した解決策は時々機能しましたが、多くのエッジケースへの道があったので、カーソルの前後のテキストの量を検討することになりました。それが0文字の場合、私は最初または最後にいました。

handle_keydown = function(e) {
  // Get the current cusor position
  range = window.getSelection().getRangeAt(0)
  // Create a new range to deal with text before the cursor
  pre_range = document.createRange();
  // Have this range select the entire contents of the editable div
  pre_range.selectNodeContents(this);
  // Set the end point of this range to the start point of the cursor
  pre_range.setEnd(range.startContainer, range.startOffset);
  // Fetch the contents of this range (text before the cursor)
  this_text = pre_range.cloneContents();
  // If the text's length is 0, we're at the start of the div.
  at_start = this_text.textContent.length === 0;
  // Rinse and repeat for text after the cursor to determine if we're at the end.
  post_range = document.createRange();
  post_range.selectNodeContents(this);
  post_range.setStart(range.endContainer, range.endOffset);
  next_text = post_range.cloneContents();
  at_end = next_text.textContent.length === 0;
}

マウスの操作が必要なため、これを単体テストする方法が完全にはわからないため、他のエッジケースがあるかどうかはまだ完全にはわかりません。おそらく、これを処理するライブラリがどこかにあります。

于 2011-09-19T15:48:04.287 に答える