2012-02-07 12 views
15

Vorrei trovare e tenere traccia del "numero di riga" (righe) del cursore in un'area di testo. (L'immagine più grande è quella di analizzare il testo sulla linea ogni volta che una nuova riga viene creata/modificata/selezionata, se ovviamente il testo non è stato incollato. Ciò evita di analizzare l'intero testo necessariamente a intervalli regolari).Individuare il numero di riga (riga) del cursore in un'area di testo

Ci sono un paio di messaggi su StackOverflow, ma nessuno di essi risponde in modo specifico alla mia domanda, la maggior parte delle domande riguarda la posizione del cursore in pixel o la visualizzazione di numeri di linee oltre alla textarea.

Il mio tentativo è al di sotto, funziona bene quando si inizia alla riga 1 e non si esce dalla textarea. Fallisce quando si fa clic fuori dalla textarea e di nuovo su di essa su una linea diversa. Non riesce anche a incollare il testo perché la riga iniziale non è 1.

La mia conoscenza di JavaScript è piuttosto limitata.

<html> 

<head> 
<title>DEVBug</title> 

<script type="text/javascript"> 

    var total_lines = 1; // total lines 
    var current_line = 1; // current line 
    var old_line_count; 

    // main editor function 
    function code(e) { 

     // declare some needed vars 
     var keypress_code = e.keyCode; // key press 
     var editor = document.getElementById('editor'); // the editor textarea 
     var source_code = editor.value; // contents of the editor 

     // work out how many lines we have used in total  
      var lines = source_code.split("\n"); 
      var total_lines = lines.length; 

    // do stuff on key presses 
    if (keypress_code == '13') { // Enter 
     current_line += 1; 
    } else if (keypress_code == '8') { // Backspace 
     if (old_line_count > total_lines) { current_line -= 1; } 
    } else if (keypress_code == '38') { // Up 
     if (total_lines > 1 && current_line > 1) { current_line -= 1; } 
    } else if (keypress_code == '40') { // Down 
     if (total_lines > 1 && current_line < total_lines) { current_line += 1; } 
    } else { 
     //document.getElementById('keycodes').innerHTML += keypress_code; 
    } 

    // for some reason chrome doesn't enter a newline char on enter 
    // you have to press enter and then an additional key for \n to appear 
    // making the total_lines counter lag. 
    if (total_lines < current_line) { total_lines += 1 }; 

    // putput the data 
    document.getElementById('total_lines').innerHTML = "Total lines: " + total_lines; 
    document.getElementById('current_line').innerHTML = "Current line: " + current_line; 

    // save the old line count for comparison on next run 
    old_line_count = total_lines; 

} 

</script> 

</head> 

<body> 

<textarea id="editor" rows="30" cols="100" value="" onkeydown="code(event)"></textarea> 
<div id="total_lines"></div> 
<div id="current_line"></div> 

</body> 

</html> 
+1

per riga, vuoi dire remare? Colonna e linea non sono la stessa cosa quando si parla di testo. Non ci sono colonne quando vengono utilizzati font non monospaziali. – Anurag

+0

Scusa, sì, intendo riga. Aggiornerò il mio post originale – ethicalhack3r

risposta

23

Si consiglia di utilizzare selectionStart per eseguire questa operazione.

<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea> 
<div id="lineNo"></div> 

<script> 

    function getLineNumber(textarea, indicator) { 

     indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length; 
    } 

</script> 

questo funziona quando si cambia la posizione del cursore con il mouse pure.

+0

WOW. Non avremmo potuto chiedere una soluzione migliore! Pulisci e funziona perfettamente! Grazie mille! – ethicalhack3r

+0

siete i benvenuti :) – caleb

+18

Questa soluzione non funzionerà se ci sono interruzioni di riga nella zona di testo. Esempio: creare una textarea con 10 colonne, inserire un paio di parole in modo che il testo trabocchi a 2-3 linee - ma NON aggiungere nuove linee in esso. Il codice sopra restituirà sempre 1 perché non vi è alcun carattere "\ n" nella textarea, ma l'utente vede effettivamente più di 1 riga. Questa è la vera difficoltà con TEXTAREAs ... Sono davvero sorpreso che non ci siano API standard per questo nei browser moderni ... –

16

Questo è difficile a causa del ritorno a capo automatico. È molto semplice contare il numero di interruzioni di riga presenti, ma cosa succede quando la nuova riga è a causa del ritorno a capo automatico? Per risolvere questo problema, è utile creare un mirror (credito: github.com/jevin). Ecco l'idea:

  1. creare un mirror del textarea
  2. Invia il contenuto dall'inizio del textarea al cursore allo specchio
  3. Uso l'altezza dello specchio per estrarre la riga corrente

On JSFiddle

jQuery.fn.trackRows = function() { 
    return this.each(function() { 

    var ininitalHeight, currentRow, firstIteration = true; 

    var createMirror = function(textarea) { 
     jQuery(textarea).after('<div class="autogrow-textarea-mirror"></div>'); 
     return jQuery(textarea).next('.autogrow-textarea-mirror')[0]; 
    } 

    var sendContentToMirror = function (textarea) { 
     mirror.innerHTML = String(textarea.value.substring(0,textarea.selectionStart-1)).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br />') + '.<br/>.'; 
     calculateRowNumber(); 
    } 

    var growTextarea = function() { 
     sendContentToMirror(this); 
    } 

    var calculateRowNumber = function() { 
     if(firstIteration){ 
      ininitalHeight = $(mirror).height(); 
      currentHeight = ininitalHeight; 
      firstIteration = false; 
     } else { 
      currentHeight = $(mirror).height(); 
     } 
     // Assume that textarea.rows = 2 initially 
     currentRow = currentHeight/(ininitalHeight/2) - 1; 
     //remove tracker in production 
     $('.tracker').html('Current row: ' + currentRow); 
    } 

    // Create a mirror 
    var mirror = createMirror(this); 

    // Style the mirror 
    mirror.style.display = 'none'; 
    mirror.style.wordWrap = 'break-word'; 
    mirror.style.whiteSpace = 'normal'; 
    mirror.style.padding = jQuery(this).css('padding'); 
    mirror.style.width = jQuery(this).css('width'); 
    mirror.style.fontFamily = jQuery(this).css('font-family'); 
    mirror.style.fontSize = jQuery(this).css('font-size'); 
    mirror.style.lineHeight = jQuery(this).css('line-height'); 

    // Style the textarea 
    this.style.overflow = "hidden"; 
    this.style.minHeight = this.rows+"em"; 

    var ininitalHeight = $(mirror).height(); 

    // Bind the textarea's event 
    this.onkeyup = growTextarea; 

    // Fire the event for text already present 
    // sendContentToMirror(this); 

    }); 
}; 

$(function(){ 
    $('textarea').trackRows(); 
}); 
+2

Questa dovrebbe essere la risposta accettata. Non ho testato il codice ma almeno tenta una soluzione funzionante che gestisca le interruzioni di linea morbida. – ryandlf

+0

Lo styling è una parte obbligatoria della soluzione? Ho implementato questo senza il CSS e ho impostato la proprietà wrap textarea su "off". Se poi scrivo il testo nell'area di testo in modo tale che si allontani dal bordo dell'area di testo (forzando la visualizzazione di una barra di scorrimento orizzontale), il numero di riga viene segnalato come aumentato anche se non ho creato una nuova riga. – youcantryreachingme

Problemi correlati