2017-05-07 5 views
15

私はcontenteditable divを持っており、現在のキャレット位置にある単語を知る必要があります。私はthis solutionを試しましたが、問題は、@~のような特殊文字は認識されません。だから、~foolのように、~で始まる単語は、となりますが、私は~foolです。だから私は、選択を元に戻した後に遭遇した文字がスペースではない場合、スペースに遭遇するまで後方に移動し続けることを考慮して、解決策を修正しようとしました。それは選択の始まりになります。同様に、私はスペースを見つけるまで前進し続け、それは選択の終わりを示すでしょう。それから、その選択は私にその言葉を与えるだろう。キャレット位置を取得するために、私はthis solutionを使用しました。私のコードは以下のようになります:コンテンツ編集可能divのキャレットに特殊文字で始まる単語を取得

function getCaretPosition(editableDiv) { 
    var caretPos = 0, 
    sel, range; 
    if (window.getSelection) { 
    sel = window.getSelection(); 
    if (sel.rangeCount) { 
     range = sel.getRangeAt(0); 
     if (range.commonAncestorContainer.parentNode == editableDiv) { 
     caretPos = range.endOffset; 
     } 
    } 
    } else if (document.selection && document.selection.createRange) { 
    range = document.selection.createRange(); 
    if (range.parentElement() == editableDiv) { 
     var tempEl = document.createElement("span"); 
     editableDiv.insertBefore(tempEl, editableDiv.firstChild); 
     var tempRange = range.duplicate(); 
     tempRange.moveToElementText(tempEl); 
     tempRange.setEndPoint("EndToEnd", range); 
     caretPos = tempRange.text.length; 
    } 
    } 
    return caretPos; 
} 

function getCurrentWord() { 
    var sel, word = ""; 
    if (window.getSelection && (sel = window.getSelection()).modify) { 
     var selectedRange = sel.getRangeAt(0); 
     sel.collapseToStart(); 
     sel.modify("move", "backward", "word"); 

     while (sel.toString() != " " && getCaretPosition($("#editor").get(0)) != 0) { 
      sel.modify("move", "backward", "character"); 
      (sel = window.getSelection()).modify; 
     } 
     sel.modify("move", "forward", "character");  
     sel.modify("extend", "forward", "word"); 
     word = sel.toString(); 

     // Restore selection 
     sel.removeAllRanges(); 
     sel.addRange(selectedRange); 
    } else if ((sel = document.selection) && sel.type != "Control") { 
     var range = sel.createRange(); 
     range.collapse(true); 
     range.expand("word"); 
     word = range.text; 
    } 
    return word; 
} 

$(function() { 

    $(document).on('keyup keydown paste cut mouseup',"#editor", function() { 
     var word = getCurrentWord(); 
     console.log(word); 
    }); 
}); 

しかし、これはまったく機能しません。それは問題ではありません。問題2は、画像に画像があり、ユーザが画像をクリックしても、ハンドラは画像の前に最後の単語を戻し続けますが、空の文字列が必要です。誰も私がこれら2つの問題を解決するのを助けることができます

+0

私はその男であることを憎むが、それはあなたが一緒にあなたのニーズに合わせて作業溶液を入れるために必要なすべてを持っている2件の回答の間のように聞こえます。いずれかの答えをマークする必要はありません。あなた自身のために何かを稼働させるための十分なソリューションがあると思ってください。P –

+0

私は自分自身で何かを試しています。 – SexyBeast

+0

私の謝罪、私はあなたが怠け者であることを暗示するつもりはなかった。ちょうど2つの答えの間に私は答えが潜んでいると思うことを意味した。 –

答えて

2

ここではかなりベアボーンの例です。例文を含むdivがあります。

<div contenteditable onclick="getCaretCharacterOffsetWithin(this)">some ~test content</div> 

ここにスクリプトがあります。 divをクリックすると、カーソルがどこにあっても現在の位置が取得され、現在の単語が吐き出されます。この単語には特殊文字を含めることができ、スペースのみが表示されます。

作業その相続人一例
function getCaretCharacterOffsetWithin(element) { 
    var caretOffset = 0; 
    var doc = element.ownerDocument || element.document; 
    var win = doc.defaultView || doc.parentWindow; 
    var sel; 
    if (typeof win.getSelection != "undefined") { 
     sel = win.getSelection(); 
     if (sel.rangeCount > 0) { 
      var range = win.getSelection().getRangeAt(0); 
      var preCaretRange = range.cloneRange(); 
      preCaretRange.selectNodeContents(element); 
      preCaretRange.setEnd(range.endContainer, range.endOffset); 
      caretOffset = preCaretRange.toString().length; 
     } 
    } else if ((sel = doc.selection) && sel.type != "Control") { 
     var textRange = sel.createRange(); 
     var preCaretTextRange = doc.body.createTextRange(); 
     preCaretTextRange.moveToElementText(element); 
     preCaretTextRange.setEndPoint("EndToEnd", textRange); 
     caretOffset = preCaretTextRange.text.length; 
    } 
    console.log('caretOffset', caretOffset); 
    word = getWordAtPosition(caretOffset, element); 
    console.log('word', word); 
    return caretOffset; 
} 

function getWordAtPosition(position, element) { 
    var total_text = element.innerHTML; 
    var current_word = ""; 
    var i = 0; 
    var word_found = false; 
    while(i < total_text.length) { 
    if(total_text[i] != ' ') 
     current_word += total_text[i]; 
    else if(word_found) 
     return current_word; 
    else 
     current_word = ""; 
    if(i == position) 
     word_found = true; 
    i++; 
    } 
    return current_word; 
} 

https://codepen.io/anon/pen/dWdyLV

+1

うーん。ほとんど動作します。ただし、あなたが指定したコードの中で、単語の最後をクリックすると、 '〜test'という単語の最後にカーソルが点滅します。表示される単語は' content'です。スペース。第2に、単語の先頭をクリックすると、単語の最初の文字の直前でカーソルが点滅し、 '〜test'という単語に対しては、' hello'のような他の単語に対して '〜test'が返されます'〜'で始まり、 ' ' – SexyBeast

+0

を返します。言い換えれば、 '〜test'という単語を太字にすると、返される単語は'〜test'ではなく '〜test'内容は '〜test'となります。 – SexyBeast

+0

最初の考え: '〜test 'が望ましくないと選択されていますか?一番簡単なことは、単語の分離を示す特殊文字の特定のリストを書いてそこから出ることだと思います。 –

5

を私はキャレット位置から単語を取得するために、基本的な文字列メソッドを使用するgetCurrentWord()機能を変更しました。関数は要素と位置を受け取り、その位置にある単語を返します。

以下は更新された機能です。

function getCurrentWord(el, position) { 
    // Get content of div 
    var content = el.textContent; 

    // Check if clicked at the end of word 
    position = content[position] === ' ' ? position - 1 : position; 

    // Get the start and end index 
    var startPosition = content.lastIndexOf(' ', position); 
    var endPosition = content.indexOf(' ', position); 

    // Special cases 
    startPosition = startPosition === content.length ? 0 : startPosition; 
    endPosition = endPosition === -1 ? content.length : endPosition; 

    return content.substring(startPosition + 1, endPosition); 
} 

この関数は、最初に要素の内容を取得します。次に、単語の最後にユーザがクリックしたかどうかをチェックし、そうであれば、位置から1を引いて、indexOflastIndexOfが正しく動作するようにします。

開始位置と終了位置には、処理する必要がある特殊なケースが2つあります。最初に、最後の要素をクリックします。このため、startPosition-1になります。最後の単語の後にスペースがない可能性があるからです。

第2に、最初の単語をクリックすると、endPosition-1になります。最初の単語の前にスペースがない可能性があるからです。

これらの2つの条件は、最初の文字の前にスペースがあり、最後の文字の後にスペースがあっても機能します。

indexOfおよびlastIndexOfは、単語の前後のスペースを検索し、それらのインデックスを使用してsubstringがその位置に単語を与えます。

ここにはlive demoがテストされます。

$(function() { 
 
    function getCaretPosition(editableDiv) { 
 
    var caretPos = 0, 
 
     sel, range; 
 
    if (window.getSelection) { 
 
     sel = window.getSelection(); 
 
     if (sel.rangeCount) { 
 
     range = sel.getRangeAt(0); 
 
     if (range.commonAncestorContainer.parentNode == editableDiv) { 
 
      caretPos = range.endOffset; 
 
     } 
 
     } 
 
    } else if (document.selection && document.selection.createRange) { 
 
     range = document.selection.createRange(); 
 
     if (range.parentElement() == editableDiv) { 
 
     var tempEl = document.createElement("span"); 
 
     editableDiv.insertBefore(tempEl, editableDiv.firstChild); 
 
     var tempRange = range.duplicate(); 
 
     tempRange.moveToElementText(tempEl); 
 
     tempRange.setEndPoint("EndToEnd", range); 
 
     caretPos = tempRange.text.length; 
 
     } 
 
    } 
 
    return caretPos; 
 
    } 
 

 
    function getCurrentWord(el, position) { 
 
    var word = ''; 
 

 
    // Get content of div 
 
    var content = el.textContent; 
 

 
    // Check if clicked at the end of word 
 
    position = content[position] === ' ' ? position - 1 : position; 
 

 
    // Get the start and end index 
 
    var startPosition = content.lastIndexOf(' ', position); 
 
    startPosition = startPosition === content.length ? 0 : startPosition; 
 
    var endPosition = content.indexOf(' ', position); 
 
    endPosition = endPosition === -1 ? content.length : endPosition; 
 

 
    return content.substring(startPosition + 1, endPosition); 
 
    } 
 

 

 
    $('#editor').on('keyup keydown paste cut mouseup', function() { 
 
    var caretPosition = getCaretPosition(this); 
 
    var word = getCurrentWord(this, caretPosition); 
 
    console.log(word); 
 
    }); 
 
});
div { 
 
    font-size: 18px; 
 
    line-height: 1.5em; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="editor" contenteditable> 
 

 

 

 
    Lorem !p$um dolor $!t @met, con$ectetur @d!p!$!c!ng el!t, $ed do e!u$mod tempor !nc!d!dunt ut [email protected] et dolore [email protected]@ @[email protected] Ut en!m @d m!n!m [email protected], qu!$ no$trud [email protected]!on [email protected] [email protected]!$ n!$! ut @l!qu!p ex [email protected] commodo [email protected] Du!$ @ute !rure dolor 
 
    !n reprehender!t !n [email protected] vel!t e$$e c!llum dolore eu [email protected] [email protected] [email protected][email protected] 
 
</div>

+1

まだ何トンものエラーがあります。例えば、あなたがあなたのフィドルで与えたコンテンツの例では、3番目の単語 - dolorをクリックし、それを太字にするために 'CTRL-B'を実行し、再度それをクリックすれば、間違った単語を与え始めます。単語をダブルタップして選択すると、その単語の代わりに間違った単語が記録されます。 – SexyBeast

関連する問題