2012-02-07 14 views
15

Me gustaría averiguar y realizar un seguimiento del 'número de línea' (filas) del cursor en un área de texto. (La 'imagen más grande' es analizar el texto en la línea cada vez que se crea/modifica/selecciona una nueva línea, si, por supuesto, el texto no se pegó. Esto guarda el análisis del texto completo innecesariamente a intervalos establecidos).Averigüe el número de 'línea' (fila) del cursor en un área de texto

Hay un par de publicaciones en StackOverflow, sin embargo, ninguna de ellas responde específicamente mi pregunta, la mayoría de las preguntas son para la posición del cursor en píxeles o para mostrar números de líneas además del área de texto.

Mi intento está abajo, funciona bien al comenzar en la línea 1 y no salir del área de texto. Falla al hacer clic fuera del área de texto y regresar a ella en una línea diferente. También falla al pegar texto porque la línea de inicio no es 1.

Mi conocimiento de JavaScript es bastante limitado.

<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

por línea, qué se refiere la fila? La columna y la línea no son lo mismo cuando se habla de texto. No hay columnas cuando se usan fuentes que no son de espacio simple. – Anurag

+0

Lo siento, sí, me refiero a la fila. Actualizaré mi publicación original. – ethicalhack3r

Respuesta

23

Desea utilizar selectionStart para hacerlo.

<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> 

Esto funciona cuando también se cambia la posición del cursor con el mouse.

+0

WOW. ¡No podría haber pedido una mejor solución! Limpio y funciona a la perfección! ¡Muchas gracias! – ethicalhack3r

+0

de nada :) – caleb

+18

Esta solución no funcionará si hay saltos de línea suaves en el área de texto. Ejemplo: haga un área de texto con 10 columnas, coloque un par de palabras para que el texto se desborde a 2-3 líneas, pero NO agregue líneas nuevas. El código anterior siempre devolverá 1 porque no hay un carácter "\ n" en el área de texto, pero el usuario realmente ve más de 1 fila. Esa es la verdadera dificultad con TEXTAREA ... Estoy realmente sorprendido de que no haya ninguna API estándar para esto en los navegadores modernos ... –

16

Esto es difícil debido al ajuste de palabras. Es muy fácil contar el número de saltos de línea presentes, pero ¿qué sucede cuando la nueva fila se debe a un ajuste de palabras? Para resolver este problema, es útil crear un espejo (crédito: github.com/jevin). Esta es la idea:

  1. crear una réplica del área de texto
  2. enviar el contenido desde el principio del área de texto para el cursor hasta el espejo
  3. Use la altura del espejo para extraer la fila actual

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

Esta debería ser la respuesta aceptada. No he probado el código, pero al menos intenta una solución de trabajo que maneja los saltos de línea suave. – ryandlf

+0

¿El estilo es una parte obligatoria de la solución? Implementé esto sin CSS y configuré mi propiedad textarea wrap en 'off'. Si luego escribo texto en el área de texto de manera que se ejecute fuera del borde del área de texto (obligando a que aparezca una barra de desplazamiento horizontal), el número de fila se reporta como aumentado aunque no haya creado una nueva fila. – youcantryreachingme

Cuestiones relacionadas