2014-10-01 21 views
13

Istnieje html tak:Przywracanie pozycji kursora po zmianie contenteditable

<div contenteditable="true" class="value research-form thumbnail"> 
Some text here 
</div> 

i zawartości div powinien dynamicznie wyróżnić kilka słów podczas gdy użytkownik wpisze np zrobić coś takiego:

<div contenteditable="true" class="value research-form thumbnail"> 
Some text here <span style="background-color: yellow">highlight</div> it 
</div> 
<script> 
    $(document).ready(function() { 
     var input = $('#textarea').on('input', function (event) { 
      var newText = input.text().replace('highlight', '<span style="background-color: yellow">highlight</div>'); 
      input.html($.parseHTML(newText)); 
     }); 
    }); 
</script> 

Ale jest problem: gdy odświeżam tekst w kursie div porusza się na początku tekstu na wejściu.

Czy są jakieś sposoby na przywrócenie położenia kursora po zmianie zawartości podlegającej wartości? A może jest inny sposób na uzyskanie tego samego efektu?

+1

Spróbuj zapisać pozycję kursora (patrz http://stackoverflow.com/questions/4767848/get-caret-cursor-position-in-contenteditable-area-containing- html-content), a następnie ustawienie go ponownie (zobacz http://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div) po input.html (...). Myślę, że masz tu również inny problem: w twoim przykładzie "wyróżnij" słowo będzie zawijane w nowy zakres przy każdym edytowaniu tekstu. Prawdopodobnie powinieneś zamienić zawijane słowa na symbole zastępcze przed dodaniem nowych przęseł, a następnie zastąpić znaki zastępcze. – Qwerty

+0

Jeśli masz rozwiązanie spełniające Twoje oczekiwania, powinieneś dodać je jako odpowiedź i wybrać. http://stackoverflow.com/help/self-answer –

+0

@JasonSperske done – Tdm

Odpowiedz

8

Znalazłem rozwiązanie.

Oto kompletny kod:

<div class="container" style="margin-top: 10px"> 

    <div class="thumbnail value" contenteditable="true"> 

    </div> 

</div> 

<script> 
    $(document).ready(function() { 
     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; 
      } 
      return caretOffset; 
     } 

     function setCaretPosition(element, offset) { 
      var range = document.createRange(); 
      var sel = window.getSelection(); 

      //select appropriate node 
      var currentNode = null; 
      var previousNode = null; 

      for (var i = 0; i < element.childNodes.length; i++) { 
       //save previous node 
       previousNode = currentNode; 

       //get current node 
       currentNode = element.childNodes[i]; 
       //if we get span or something else then we should get child node 
       while(currentNode.childNodes.length > 0){ 
        currentNode = currentNode.childNodes[0]; 
       } 

       //calc offset in current node 
       if (previousNode != null) { 
        offset -= previousNode.length; 
       } 
       //check whether current node has enough length 
       if (offset <= currentNode.length) { 
        break; 
       } 
      } 
      //move caret to specified offset 
      if (currentNode != null) { 
       range.setStart(currentNode, offset); 
       range.collapse(true); 
       sel.removeAllRanges(); 
       sel.addRange(range); 
      } 
     } 

     function onInput(event) { 
      var position = getCaretCharacterOffsetWithin(input.get(0)); 
      var text = input.text(); 
      text = text.replace(new RegExp('\\btest\\b', 'ig'), '<span style="background-color: yellow">test</span>'); 
      input.html($.parseHTML(text)); 
      setCaretPosition(input.get(0), position); 
     } 

     var input = $('.value').on('input',onInput); 

     //content should be updated manually to prevent aditional spaces 
     input.html('simple input test example'); 
     //trigger event 
     onInput(); 
    }); 
</script> 
+0

To jest dobre rozwiązanie w twoim szczególnym przypadku: jeśli wyłączysz nowe linie w twoich contentedtibales. W przeciwnym razie skrypt, który uzyska przesunięcie kursora, zignoruje nowe elementy linii, takie jak
i ustawia pozycję kursora w niewłaściwym miejscu (przed elementami
). –

Powiązane problemy