2010-10-13 8 views
18

¿Es posible cambiar el carácter que se ha ingresado al presionar una tecla, sin hacerlo manualmente?¿Puedo cambiar condicionalmente el carácter ingresado en una entrada al presionar una tecla?

Por ejemplo, si quiero forzar las letras mayúsculas en base a alguna condición, que sería bueno para hacer lo siguiente:

function onKeypressHandler(e) 
{ 
    if (condition) 
    { 
     e.which -= 32; 
    } 
} 

Pero por supuesto que no funciona.

NOTA: Este esno un uppercasing a través de la junta, pero sólo caracteres específicos.

Tal vez quiero decir if (e.which >= 97 && e.which <= 102) o if (Wind.Direction == 'South') o lo que sea - la condición en sí no es importante, pero la uppercasing sólo debe aplicarse al carácter actual no toda la entrada.


Lo puedo hacer añadiendo manualmente el carácter modificado, pero esta es una manera fea y desordenada de hacerlo, y probablemente más lenta de lo que podría ser.

function onKeypressHandler(e) 
{ 
    if (condition) 
    { 
     $j(this).val($j(this).val() + String.fromCharCode(e.which - 32)); 
     return false; 
    } 
} 

Un defecto específico con este método - si se selecciona todo el texto de entrada y entrar en una clave, si cae en esto, entonces no elimina el contenido existente, sino que simplemente añade al contenido que el usuario desea quitar. (Tendría que investigar la detección de cualquier texto seleccionado para resolver eso, lo que hace que este sea aún más feo.)

¿Alguien puede proporcionar una mejor solución?

+0

¿Cómo manejaría pegar, deshacer/rehacer, arrastrar y soltar u otros casos de múltiples caracteres siendo ingresado al mismo tiempo, ¿o no es tan importante? –

+0

Andy, eso no es muy importante aquí, pero aún sería útil manejarlo - ¿Supongo que tendría que involucrar caminar la cuerda manualmente, dentro del evento onchange? –

+1

O los eventos * oninput * y * onpropertychange *. Esbocé estos en mi blog hace poco tiempo - http://whattheheadsaid.com/2010/09/effectively-detecting-user-input-in-javascript y tengo un plugin jQuery casi completo para ello en las obras. –

Respuesta

17

Lo siguiente hará el trabajo. Se basa en an answer I wrote to another question. Personalice la función transformTypedChar para satisfacer sus necesidades; mi ejemplo solo capitaliza las letras a-g.

Si necesita esto en un área de texto en lugar de <input type="text">, tenga en cuenta que hay problemas en IE < = 8 con saltos de línea que el siguiente código no maneja en aras de la brevedad. Puede encontrar la función de navegador cruzado para la obtención de la selección dentro de un área de texto aquí: Is there an Internet Explorer approved substitute for selectionStart and selectionEnd?

function transformTypedChar(charStr) { 
    return /[a-g]/.test(charStr) ? charStr.toUpperCase() : charStr; 
} 

document.getElementById("your_input_id").onkeypress = function(evt) { 
    var val = this.value; 
    evt = evt || window.event; 

    // Ensure we only handle printable keys, excluding enter and space 
    var charCode = typeof evt.which == "number" ? evt.which : evt.keyCode; 
    if (charCode && charCode > 32) { 
     var keyChar = String.fromCharCode(charCode); 

     // Transform typed character 
     var mappedChar = transformTypedChar(keyChar); 

     var start, end; 
     if (typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") { 
      // Non-IE browsers and IE 9 
      start = this.selectionStart; 
      end = this.selectionEnd; 
      this.value = val.slice(0, start) + mappedChar + val.slice(end); 

      // Move the caret 
      this.selectionStart = this.selectionEnd = start + 1; 
     } else if (document.selection && document.selection.createRange) { 
      // For IE up to version 8 
      var selectionRange = document.selection.createRange(); 
      var textInputRange = this.createTextRange(); 
      var precedingRange = this.createTextRange(); 
      var bookmark = selectionRange.getBookmark(); 
      textInputRange.moveToBookmark(bookmark); 
      precedingRange.setEndPoint("EndToStart", textInputRange); 
      start = precedingRange.text.length; 
      end = start + selectionRange.text.length; 

      this.value = val.slice(0, start) + mappedChar + val.slice(end); 
      start++; 

      // Move the caret 
      textInputRange = this.createTextRange(); 
      textInputRange.collapse(true); 
      textInputRange.move("character", start - (this.value.slice(0, start).split("\r\n").length - 1)); 
      textInputRange.select(); 
     } 

     return false; 
    } 
}; 
+0

Gracias Tim, parece que también está manejando el nuevo problema de selección de texto que acabo de encontrar. Lo probaré y veré cómo funciona. –

+0

OK. Acabo de agregar una nota sobre el uso de esto con textareas. –

+1

+1 buena respuesta muy inteligente –

-1

¿Se puede usar css?

<input type="text" style="text-transform: uppercase;" /> 
+2

Eso no cambia el valor de entrada real y, lo que es más importante, no se aplica condicionalmente. –

+1

¿Podría hacer una mayúscula cuando está procesando el valor enviado? ¿Qué quieres decir condicionalmente? –

+0

He actualizado la pregunta para aclarar: solo quiero (tal vez) mayúscula el carácter actual, no toda la cadena, y si la mayúsculo depende de una condición if (la comprobación precisa no es importante para la pregunta). –

0

No estoy seguro de lo que quieres, pero ¿funcionará?

$('#my_element').keyup(function(){ $(this).val().toUpperCase(); }); 

o utilizar una cadena de sub para conseguir el último carácter presionado y hacer toUpperCase() al respecto?

(psst ... también puede usar la tecla o la tecla).

+0

Una vez más, eso no es condicional, y toUpperCase no es realmente una mejora sobre el método String.fromCharCode(). –

+0

¿qué quieres decir con condicional? –

+0

He actualizado la pregunta para aclarar: solo quiero (tal vez) mayúscula el carácter actual, no toda la cadena, y si la mayúsculo depende de una condición if (la comprobación precisa no es importante para la pregunta). –

1

¿Qué tal si se previene la acción predeterminada y luego se activa la tecla? Algo como,

function onKeypressHandler(e) 
{ 
    if (condition) 
    { 
     e.preventDefault(); 
     // create new event object (you may clone current e) 
     var ne = new jQuery.Event("keypress"); 
     ne.which = e.which - 32; 
     $(e.target).trigger(ne); // you may have to invoke with setTimeout 
    } 
} 
+0

No funcionará. No puede simular los efectos de una pulsación de tecla en el navegador. –

+0

Doh! Esto parecía prometedor hasta que vi el comentario de Tim. Buena idea de todos modos. :( –

+0

@Tim, gracias por la información. Por cierto, el ejemplo de jquery docs usa .keypress() para desencadenar el evento. Entonces, ¿qué sucede en ese caso? ¿Se invoca solo el controlador de eventos sin que el control reciba el carácter? – VinayC

1

Tienes que ver esto .. yo estaba muy feliz conmigo mismo después de conseguir que funcione ..

Obviamente, debería incluir criterios suficientes para evitar entrar en un círculo aquí.

El código siguiente devuelve falso cuando la condición se evalúa como verdadera, pero dispara el mismo evento con un código de caracteres diferente que no devuelve falso.

document.getElementById("input1").onkeypress = Handler; 
function Handler(e) 
{ 
    e = e || window.event; 
    if (e.charCode == 97) 
    { 
     var evt = document.createEvent("KeyboardEvent"); 
     evt.initKeyEvent("keypress",true, true, window, false, false,false, false, 0, e.charCode -32); 
     this.dispatchEvent(evt); 
     return false; 
    } 
    return true; 
} 

podría utilizar fireEvent en IE ... que utilizan http://help.dottoro.com/ljrinokx.php y https://developer.mozilla.org/en/DOM/event.initKeyEvent para referencia

+0

Interesante. Esto solo funciona en Mozilla, sin embargo. Afortunadamente, su alcance parece limitado: al intentar activar atajos de teclado como Ctrl-B (para marcadores), Ctrl-A (seleccionar todo) no funciona. Sin embargo, no sabía que pudieras hacer tanto. –

+0

no exactamente ... IE también admite eventos de activación ... en lugar de dispatchEvent, utiliza fireEvent y para crear el evento, utiliza object.createEventObject. Ver http://help.dottoro.com/ljhlvomw.php. Estoy en Linux, así que no puedo ayudarte con el código/prueba. Pero parece factible –

+0

Parece que el código para el manejo de eventos de mouse de crossbrowser ya se proporciona en ese enlace. –

Cuestiones relacionadas