2010-07-20 18 views
13

Ho una textarea html che verrà aggiornata periodicamente tramite javascript.aggiornamento valore textarea, ma mantenere la posizione del cursore

quando faccio questo:

$("#textarea").val(new_val); 

il cursore si sposta alla fine del testo.

Desidero aggiornare il testo senza modificare la posizione del cursore. Inoltre, se l'utente ha selezionato un intervallo di testo, l'evidenziazione deve essere preservata.

risposta

23

Ecco una coppia di funzioni che ottengono e impostano la posizione di selezione/cursore in un'area di testo in tutti i principali browser.

Nota: se non è necessario per supportare IE < = 8, basta usare i selectionStart e selectionEnd proprietà (MDN). Tutto il codice complicato di seguito è solo lì per supportare le vecchie versioni di IE.

function getInputSelection(el) { 
    var start = 0, end = 0, normalizedValue, range, 
     textInputRange, len, endRange; 

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { 
     start = el.selectionStart; 
     end = el.selectionEnd; 
    } else { 
     range = document.selection.createRange(); 

     if (range && range.parentElement() == el) { 
      len = el.value.length; 
      normalizedValue = el.value.replace(/\r\n/g, "\n"); 

      // Create a working TextRange that lives only in the input 
      textInputRange = el.createTextRange(); 
      textInputRange.moveToBookmark(range.getBookmark()); 

      // Check if the start and end of the selection are at the very end 
      // of the input, since moveStart/moveEnd doesn't return what we want 
      // in those cases 
      endRange = el.createTextRange(); 
      endRange.collapse(false); 

      if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { 
       start = end = len; 
      } else { 
       start = -textInputRange.moveStart("character", -len); 
       start += normalizedValue.slice(0, start).split("\n").length - 1; 

       if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { 
        end = len; 
       } else { 
        end = -textInputRange.moveEnd("character", -len); 
        end += normalizedValue.slice(0, end).split("\n").length - 1; 
       } 
      } 
     } 
    } 

    return { 
     start: start, 
     end: end 
    }; 
} 

function offsetToRangeCharacterMove(el, offset) { 
    return offset - (el.value.slice(0, offset).split("\r\n").length - 1); 
} 

function setInputSelection(el, startOffset, endOffset) { 
    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { 
     el.selectionStart = startOffset; 
     el.selectionEnd = endOffset; 
    } else { 
     var range = el.createTextRange(); 
     var startCharMove = offsetToRangeCharacterMove(el, startOffset); 
     range.collapse(true); 
     if (startOffset == endOffset) { 
      range.move("character", startCharMove); 
     } else { 
      range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset)); 
      range.moveStart("character", startCharMove); 
     } 
     range.select(); 
    } 
} 

Quando si modifica il valore del textarea, prima salvare la selezione, quindi ripristinarlo in seguito:

var t = document.getElementById("textarea"); 
var sel = getInputSelection(t); 
t.value = some_new_value; 
setInputSelection(t, sel.start, sel.end); 
+0

fa il lavoro 'setInputSelection' funzione solo in IE? Sto chiedendo perché il metodo 'createTextRange' non esiste (per gli elementi di input) negli altri browser, in modo che venga generato un errore. –

+0

@ Šime: Oh, sì, mi dispiace. Copia/incollato da una domanda solo IE. Rivedere ora ... –

+0

@ Šime: ... e fatto. –

Problemi correlati