2013-05-24 69 views
7

私は複数のタグ(br、b、u、i)とテキストを持つcontentedit divを持っており、divを基準にしてキャレットの位置を取得する必要があります。例えばタグを含むcontenteditable divのキャレット位置を取得

<div id="h" contenteditable="true">abc<b>def<br>ghi</b>jkl</div> 

カーソルがGおよびHの間にある場合、私は問題14 ことがキャレット位置を必要とするがTreeWalkerの使用を見出さ方法は、この場合では動作しないことです。 太字のタグが見つかりません。おそらく閉じていないためです。 また、いくつかの方法を試しましたが、まだ運がありません。

Firefoxで動作する必要があります。 ありがとうございます。

+0

あなたが必要な理由 この番号?数字に影響する異なるHTMLで同じDOMを表現する方法がたくさんあるので(例えば、 '
'の代わりに '
'を使用するなど)、本質的に無意味です。私はあなたがこれを望むと仮定しているので、サーバーからブラウザに送るHTML文字列に相対的なオフセットを得ることができます。 –

+0

はい...それは正確に私が番号が必要な理由です。私はいくつかの手段を試みたが、まだ成功していない。 – helldrain

+1

DOMを介して元のHTML文字列を取得する方法はありません。そのため、Ajaxでページを再要求し、HTMLを解析して現在のDOMに一致させる必要があります。それはかなりトリッキーになるだろう。 –

答えて

20

これを試しましたか? jsfiddleへ Get a range's start and end offset's relative to its parent container

直接リンク: https://jsfiddle.net/TjXEG/1/

機能コード:

function getCaretCharacterOffsetWithin(element) { 
    var caretOffset = 0; 
    if (typeof window.getSelection != "undefined") { 
     var range = window.getSelection().getRangeAt(0); 
     var preCaretRange = range.cloneRange(); 
     preCaretRange.selectNodeContents(element); 
     preCaretRange.setEnd(range.endContainer, range.endOffset); 
     caretOffset = preCaretRange.toString().length; 
    } else if (typeof document.selection != "undefined" && document.selection.type != "Control") { 
     var textRange = document.selection.createRange(); 
     var preCaretTextRange = document.body.createTextRange(); 
     preCaretTextRange.moveToElementText(element); 
     preCaretTextRange.setEndPoint("EndToEnd", textRange); 
     caretOffset = preCaretTextRange.text.length; 
    } 
    return caretOffset; 
} 

function showCaretPos() { 
    var el = document.getElementById("test"); 
    var caretPosEl = document.getElementById("caretPos"); 
    caretPosEl.innerHTML = "Caret position: " + getCaretCharacterOffsetWithin(el); 
} 

document.body.onkeyup = showCaretPos; 
document.body.onmouseup = showCaretPos; 
+7

あなたの答えをありがとう。問題は、キャレットの位置を決定する際に
が考慮されていないことです。 – helldrain

+1

@helldrainタグを含むソリューションを見つけることができたのだろうかと思います。 –

+0

にはタグの長さも含む関数があります。 ? –

3

はいくつかの実用的なソリューションがあるので、これをしなければならなかった(いくつかのテストが必要な場合があります)

基本的な考え方は次のとおりです。

  1. この方法使用のTextContent位置を得る:HTMLタグまたはエンティティに遭遇した場合、のTextContent位置

  2. に対する要素のinnerHTMLのを通してGet caret (cursor) position in contentEditable area containing HTML content

  3. 反復を次に

  4. を続け、通常の文字までを反復ここ

サンプルコード:

function getHTMLCaretPosition(element) { 
var textPosition = getCaretPosition(element), 
    htmlContent = element.innerHTML, 
    textIndex = 0, 
    htmlIndex = 0, 
    insideHtml = false, 
    htmlBeginChars = ['&', '<'], 
    htmlEndChars = [';', '>']; 


if (textPosition == 0) { 
    return 0; 
} 

while(textIndex < textPosition) { 

    htmlIndex++; 

    // check if next character is html and if it is, iterate with htmlIndex to the next non-html character 
    while(htmlBeginChars.indexOf(htmlContent.charAt(htmlIndex)) > -1) { 
    // console.log('encountered HTML'); 
    // now iterate to the ending char 
    insideHtml = true; 

    while(insideHtml) { 
     if (htmlEndChars.indexOf(htmlContent.charAt(htmlIndex)) > -1) { 
     if (htmlContent.charAt(htmlIndex) == ';') { 
      htmlIndex--; // entity is char itself 
     } 
     // console.log('encountered end of HTML'); 
     insideHtml = false; 
     } 
     htmlIndex++; 
    } 
    } 
    textIndex++; 
} 

//console.log(htmlIndex); 
//console.log(textPosition); 
// in htmlIndex is caret position inside html 
return htmlIndex; 
} 
+3

あなたは私のヒーローです。これは美しく働き、何時間も涙を貯めました。 –

関連する問題