2011-12-10 23 views
12

浮動小数点div要素をcontentEditableiframeに配置したい場合は、ユーザーが特定のキーの組み合わせを入力すると。contentEditableを使用してiframe内の現在のキャレット位置からピクセルオフセットを取得する方法

私はキャレット位置を取得する方法を知っている: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset

私はdiv要素のleftプロパティを計算するためにこれを使用することができますが、私はtopを取得する方法を見つけ出すように見えることはできません。

私が使っていた考えたもう一つの可能​​性: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode

を、オフセットを取得するためにはjQueryを使用して、それ親が長いテキスト行を持っている場合、私は最初の行の先頭位置を抽出することができるだろう。

誰もがこれを手伝ってくれますか?

答えて

12

これを実行する確実な方法は、テンポラリ要素をキャレットに挿入して(幅がゼロであることを確認する)、位置を取得してもう一度削除することです。また、DOMノードが挿入される前の状態を保証するために、テキストノードの両端を結合して(キャレットを含むテキストノードの場合)結合してください。ただし、これを行う(または編集可能なコンテンツで他の手動のDOM操作を行う)と、ブラウザの内部の元に戻すスタックが破損することに注意してください。

この理由は、the spec for the getBoundingClientRect() method of Rangeを慎重に読み取ると、getBoundingClientRect()は折りたたまれた範囲のRectを返すよう強制されないことがわかります。概念的には、文書内のすべての位置が明確な境界矩形を持つわけではありません。しかし、キャレットは画面上に物理的な位置を持っていますが、これは私の意見ではSelection APIによって提供されるべきですが、現在のところ、ブラウザにはこれを提供するものは何もありません。

+2

あなたは範囲が '左+幅&トップ+高さオフセットを取得するために' getBoundingClientRect()を使用し、その後、0から現在のキャレットの位置になるように設定できませんでした、それにキャレットを復元すると、以前のです設定? – Mottie

+3

古いスレッドですが、要素を挿入すること([execCommand( 'insertHTML') ']を使用してそれを削除することは、元に戻す/やり直しスタックを壊してしまいます。元に戻す/やり直しが重要でないかどうかは関係ありません。 – techfoobar

+0

@techfoobar:良い点、ありがとう。私は答えにメモを付け加えました。 –

7

今日この問題が発生しました。いくつかのテストの後で、私は、temorary要素を使用せずに、この作業を得ました。

IEでは、TextRangeオブジェクトのoffsetLeftおよびoffsetTopプロパティを使用して簡単に解決できます。しかし、Webkitにはいくつかの努力が必要です。

ここにテストがあります。その結果を確認できます。 http://jsfiddle.net/gliheng/vbucs/12/

var getCaretPixelPos = function ($node, offsetx, offsety){ 
    offsetx = offsetx || 0; 
    offsety = offsety || 0; 

    var nodeLeft = 0, 
     nodeTop = 0; 
    if ($node){ 
     nodeLeft = $node.offsetLeft; 
     nodeTop = $node.offsetTop; 
    } 

    var pos = {left: 0, top: 0}; 

    if (document.selection){ 
     var range = document.selection.createRange(); 
     pos.left = range.offsetLeft + offsetx - nodeLeft + 'px'; 
     pos.top = range.offsetTop + offsety - nodeTop + 'px'; 
    }else if (window.getSelection){ 
     var sel = window.getSelection(); 
     var range = sel.getRangeAt(0).cloneRange(); 
     try{ 
      range.setStart(range.startContainer, range.startOffset-1); 
     }catch(e){} 
     var rect = range.getBoundingClientRect(); 
     if (range.endOffset == 0 || range.toString() === ''){ 
      // first char of line 
      if (range.startContainer == $node){ 
       // empty div 
       if (range.endOffset == 0){ 
        pos.top = '0px'; 
        pos.left = '0px'; 
       }else{ 
        // firefox need this 
        var range2 = range.cloneRange(); 
        range2.setStart(range2.startContainer, 0); 
        var rect2 = range2.getBoundingClientRect(); 
        pos.left = rect2.left + offsetx - nodeLeft + 'px'; 
        pos.top = rect2.top + rect2.height + offsety - nodeTop + 'px'; 
       } 
      }else{ 
       pos.top = range.startContainer.offsetTop+'px'; 
       pos.left = range.startContainer.offsetLeft+'px'; 
      } 
     }else{ 
      pos.left = rect.left + rect.width + offsetx - nodeLeft + 'px'; 
      pos.top = rect.top + offsety - nodeTop + 'px'; 
     } 
    } 
    return pos; 
}; 
+0

ニースの答えの友人! –

+0

これは私の答えで言及したように、Firefoxや他のブラウザの 'range.getBoundingClientRect()'は、折りたたまれた範囲のすべてのゼロを含むRectを返すことがあります。 1つの例については、http://jsfiddle.net/CK3e8/を参照してください。 –

+0

それは本当です、時間。私は選択を1文字戻して、そこからキャレット位置を取り出そうとしました。 – osamu

関連する問題