2010-08-10 11 views
5

Estoy tratando de crear un área de texto de sangría automática y hasta ahora funciona con el siguiente código. El problema que estoy teniendo es que actualmente estoy evitando la acción predeterminada de presionar enter para calcular las pestañas en la línea y luego insertar la nueva línea.Sangría automática de área de texto "inteligente"

Esto funciona, pero quiero tener la acción predeterminada del área de texto, en el sentido de que si mantienes presionada la tecla enter, no desplaza el área de texto hasta que el símbolo de intercalación toca la fila inferior y luego la barra de desplazamiento permanece presionada en la fila inferior El código actual a continuación mantiene el cursor en el campo de visión si se utiliza en cualquier parte del área de texto, pero hace que el contenido por encima del cursor se desplace hacia arriba, lo cual es un compromiso ya que el cursor ya no desaparece. Si no hay otra solución, funcionará bien, pero espero que haya otras ideas.

var start = this.selectionStart-1; 
    var end = this.selectionEnd; 
    var sT = this.scrollTop; 
    var sH = this.scrollHeight; 
    var vH = $(this).height(); 

    var x = (sH - sT) - vH; 

    // Check if hitting enter on the first line as no newline will be found 
    if (this.value.lastIndexOf('\n',start)==-1) 
    var startSubstr = 0; 
    else 
    var startSubstr = this.value.lastIndexOf('\n',start)+1; 

    var endFirst = end - startSubstr; 

    var valueToScan = this.value.substr(startSubstr,endFirst); 
    var count = 0; 

    // Count only \t at the beginning of the line, none in the code 
    while (valueToScan.indexOf('\t')!=-1) { 
    if (valueToScan.indexOf('\t')!=0) 
     break; 
    count++; 
    valueToScan = valueToScan.substr(valueToScan.indexOf('\t')+1); 
    } 

    // Command to isert the newline, and then add the \t's found in previously 
    $(this).insertAtCaret('\n'); 
    for (var i=0;i<count;count--) { 
    $(this).insertAtCaret('\t'); 
    } 

    var sH = this.scrollHeight; 
    this.scrollTop = (sH - x) - vH; 

EDITAR Como una actualización, para eliminar cualquier confusión, Estoy intentando crear un cuadro de texto estilo IDE, así por ejemplo, en la mayoría de entornos de desarrollo si escribe el siguiente

function example(whatever) { 
    Example Stuff // And then hit enter here 

Quiero que te lleve a la misma distancia de tabulación desde el borde izquierdo como "Ejemplo de cosas" para mantener tu código más fácil de leer. Actualmente tengo esa funcionalidad, pero el problema es que estoy interceptando la tecla enter, lo que significa que tengo que proporcionar esa funcionalidad. Tengo dificultades para replicar la funcionalidad exacta de no desplazar el cuadro de texto hasta que el cursor toque el borde inferior. Entonces, si tuviera que mantener enter en la parte superior del área de texto, el cursor simplemente desplaza hacia abajo el área de texto, moviendo cualquier texto hasta que toque el borde inferior, y luego la barra de desplazamiento para el área de texto seguirá el cursor. ¿Tener sentido?

EDITAR 2etiquetas actualiza para indicar el código es con PHP

He estado trabajando en esto, mientras que este post ha estado sentado. Creo que otra opción que voy a explorar cuando tengo la oportunidad es, en lugar de evitar, solo permitir la acción predeterminada de presionar enter y leer la cadena desde lastIndexOf('\n')-1 hasta la más reciente \n para cualquier \t. Creo que me daría la cadena que estoy buscando, pero sin estropear el comportamiento del área de texto. Se actualizará nuevamente después de la prueba.

EDITAR 3 resuelve, según mi anterior actualización decidí explorar la cadena después de pulsar la tecla, preservando el comportamiento natural (Cambio la sección añadió a continuación para los interesados) y el único problema que realmente queda es que si Si mantienes presionada la tecla enter, no contará la sangría del origen de la tecla enter, lo cual está bien para mí. Voy a darle este a http://stackoverflow.com/users/15066/matyr'>matyr, aunque lo descubrí antes de que él respondiera que todavía era el más cercano.

if (this.value.lastIndexOf('\n',start-2)==-1) { 
var startSubstr = 0; 
} else { 
var startSubstr = this.value.lastIndexOf('\n',start-1)+1; 
}  
var valueToScan = this.value.substr(startSubstr,start); 

Respuesta

2

Quiero tener la acción predeterminada del área de texto

¿Qué hay de unión a keyup en lugar de keydown/keypress e inserte la pestaña después de salto de línea materna?

la barra de desplazamiento se queda con acento circunflejo en la fila inferior

Puede conservar la posición de desplazamiento mediante la restauración de scrollTop.

<!DOCTYPE html> 
<title>autoindent example</title> 
<textarea id="TA" rows="8"></textarea> 
<script> 
document.getElementById('TA').addEventListener('keyup', function(v){ 
    if(v.keyCode != 13 || v.shiftKey || v.ctrlKey || v.altKey || v.metaKey) 
    return; 
    var val = this.value, pos = this.selectionStart; 
    var line = val.slice(val.lastIndexOf('\n', pos - 2) + 1, pos - 1); 
    var indent = /^\s*/.exec(line)[0]; 
    if(!indent) return; 
    var st = this.scrollTop; 
    this.value = val.slice(0, pos) + indent + val.slice(this.selectionEnd); 
    this.selectionStart = this.selectionEnd = pos + indent.length; 
    this.scrollTop = st; 
}, false); 
</script> 
<p>(not considering IE here) 
+0

Mantener la posición de desplazamiento no es el problema, es permitir que el cursor continúe hasta la parte inferior del área de texto antes de seguirlo con cada nueva línea. Intentaré utilizar la tecla en lugar de la tecla de acceso según mi más reciente upate. – Robert

+0

if usted usa KEYUP significa que disparará cada botón, en realidad necesitamos a veces mantener presionado un botón para tener múltiples eventos. En ese caso, KEYDOWN es mejor. También el evento KEYDOWN se dispara antes de que se actualice el personaje textarea, por lo que quiere usar el.keydown (función (e) {setTimeout (función (e) {/ * SU ACCIÓN DE LLAVE PRINCIPAL * /}, 1)}); – kami

1

¿Alguna vez ha notado cómo el código de texto de Stack Overflow maneja el código? Si escribe:

function example(whatever) { 
    Example Stuff // And then hit enter here 
} 

Al principio, nada sucederá. Luego, cuando aplica sangría (ya sea escribiendo o haciendo clic en el botón 101010), pone un fondo diferente en el código. Luego, después de esperar un poco, la sintaxis colorea el código. Pero si comienza a escribir de nuevo, vuelve a negro/blanco.

Creo que un enfoque similar podría funcionar para usted.En lugar de tratar de atar todo con el evento de pulsación de tecla enter, lo que debe hacer es:

  1. Conexión para un evento normal onKeySomething, pero no sólo tiene que buscar "entrar"; después de cada pulsación de tecla:

    1A. Establezca alguna variable global (por ejemplo, temporizador) a nueva Fecha();

    1B. setTimeout (X, timeoutFunction) donde X es el tiempo que desea esperar después de que el usuario deja de escribir

  2. Create timeoutFunction; esta función debería verificar la variable global "timer" y si es nueva Date() - timer> X trigger realFunction()

  3. actualFunction puede analizar el contenido de la tabla de texto, sangrar las cosas como quieras y nada interrumpirá el flujo normal de las cosas para el usuario

sé que esto no es del todo cómo se comportan "real" del IDE, pero teniendo en cuenta las limitaciones de la JS y la web, puede muy bien ser el mejor enfoque para usted.

+0

El objetivo del proyecto es poder codificar directamente en el área de texto y limpiar el código una vez que el usuario finaliza. – Robert

+0

Aclaración, * no para limpiar el código después de que el usuario termine de escribir. Prefiero el tiempo real como un IDE. Siempre hay una manera de hacer algo, solo tienes que ser lo suficientemente creativo. Estoy seguro de que finalmente encontraré la forma;) – Robert

+0

Bueno, no digo que su enfoque sea imposible, pero ... hay que tener en cuenta que la mayoría de los usuarios no ejecutan Google Chrome con un quad core/12 gigs de RAM; en sistemas normales que ejecutan IE/Firefox, el rendimiento de JS es poco convincente. Por lo tanto, incluso si encuentra una solución "perfecta", probablemente sea muy decepcionante para la mayoría de sus usuarios debido al retraso en el rendimiento de JS.(PD: si puedes confiar en un buen hardware + Chrome, no importa). Para decirlo de otra manera, estoy seguro de que las personas SO habrían hecho que su área de texto sea más receptiva si pudieran ... pero no lo han hecho (debido a estas limitaciones). – machineghost

0

¿Qué le parece subclasificar el cuadro de texto y manejar manualmente el WndProc? Esto le proporciona un control mucho más detallado y abordará la repetición de la tecla de tipo (KeyPress y eventos similares solo disparan una vez cuando mantiene presionada la tecla).

public class MyTextBox : System.Windows.Forms.TextBox 
{ 
    protected override void WndProc(ref Message m) 
    { 
     // Let the O/S handle the key first 
     base.WndProc(ref m); 

     // Then, if it's the return key, append tabs 
     int numTabs = 3;     // TODO: insert your own value here 
     const int WM_CHAR = 0x0102; 
     if(m.Msg == WM_CHAR && (char)m.WParam == '\r') 
     { 
      m.WParam = new IntPtr('\t'); // Recycle m since base is done with it 
      for (int i = 0; i < numTabs; i++) 
       WndProc(ref m); 
     } 
    } 
} 
+0

Debo explicar que esto se hace en Javascript/PHP. – Robert

+0

¿Por qué alguien me votó? No fue exactamente obvio desde la publicación original. :( –

Cuestiones relacionadas