Laboratorio: shortcuts en formularios
Algo a lo que suelo estar acostumbrado es a usar el teclado para realizar ciertas acciones (shortcuts), cuando estás 8 horas diarias delante de un ordenador, si no haces uso de los shortcuts, perderás mucho tiempo moviendo el ratón de un lado para otro.
Antes el uso estaba más restringido a las aplicaciones de escritorio (CTRL + S para guardar el documento, ALT + F4 para cerrar la ventana, …), pero ahora que cada vez se usa con más frecuencia aplicaciones web, se echan en falta estas facilidades. Aunque hay que decir que últimamente se ven con más frecuencia: TAB + INTRO para enviar un correo en GMail (claro que esta no se programa), CONTROL + S para guardar una entrada en Blogger, …
El desarrollo para esta funcionalidad es bastante sencillo, se trata de capturar el evento del teclado en el elemento HTML que deseemos, en nuestro caso en un textarea para escribir entradas en un blog (por ejemplo).
Tampoco es tan sencillo como capturar el evento del teclado, hay que capturar realmente el evento de “apretar” una tecla (onkeydown), para evitar que se realice la acción por defecto cuando “soltamos” la tecla (onkeyup).
Otra dificultad a la que nos enfrentamos es la de evitar que cierto juego de teclas ejecuten la acción predeterminada por el navegador. Por ejemplo, en Firefox, si pulso CTRL + S me querrá guardar la página como un HTML en mi disco duro, cuando yo lo que quiero es enviar el formulario al servidor para guardarlo. Para evitar el comportamiento por defecto, hay que “anular” los eventos en el elemento body.
Los eventos yo prefiero manejarlos llamando dentro del evento en la etiqueta HTML, pasándole como parámetro el objeto event:
<textarea onkeydown="shortcut(event)" ... ></textarea>
El objeto event solo existe en IE (para variar), en Firefox, se pasa el evento como primer parámetro de la función, por lo cual en firefox, al no existir event, se le pasa automáticamente el objeto evento (en este caso KeyboardEvent), asà nos ahorramos el trabajo de ir preguntando que tipo de navegador es y tener que buscar el objeto event. Una vez ya tenemos en nuestro poder el objeto evento, para acceder a la tecla pulsada, solo tenemos que recuperar el valor de keyCode, que nos dará un número que representa la tecla pulsada, para saber si está pulsada la tecla control o alt, solo tendremos que chequear el valor de ctrlKey y altKey. Para saber el valor de las teclas que queremos capturar, os recomiendo que useis un alert y vayáis apuntando los números que os salen cuando pulsáis las teclas.
Para cancelar el evento y que no siga con lo predeterminado, hay que usar el siguiente código, el cual sirve para IE y para Firefox, aunque creo que ninguno de los dos es estándar:
evt.cancelBubble = true;
// Para Firefox
if (evt.stopPropagation) {
evt.preventDefault();
}
En el ejemplo que os voy a pasar, he capturado CONTROL+S para guardar el documento y CONTROL+B para poner en negrita el texto seleccionado dentro del textarea. Para obtener el texto seleccionado, es necesario el siguiente código (incluyo el añadir la etiqueta que deseamos):
if (obj.createTextRange) { // IE
var r = document.selection.createRange();
texto = r.text;
r.text = '<'+etiqueta+'>'+texto+'</'+etiqueta+'>'
} else if (obj.setSelectionRange) { // Firefox
// Posicion inicial en el string del texto seleccionado
var ini = obj.selectionStart;
// Posicion final en el string del texto seleccionado
var fin = obj.selectionEnd;
// Obtengo el substring
obj.value = obj.value.substring(0, ini)+'<'+etiqueta+'>'+obj.value.substring(ini, fin)+'</'+etiqueta+'>'+obj.value.substring(fin);
// Selecciono lo que estaba seleccionado anteriormente más las etiquetas
obj.selectionStart = fin+5+(etiqueta.length*2);
obj.selectionEnd = fin+5+(etiqueta.length*2);
}
El código necesario para realizar los shortcuts serÃa el siguiente:
<script type="text/javascript">
// Controla la pulsación de teclas
function shortcut(evt) {
if (evt.keyCode == 83 && evt.ctrlKey) { // CONTROL+S
// Simulacion de guardado
setTimeout('alert("GUARDADO")', 1000);
} else if (evt.keyCode == 66 && evt.ctrlKey) { // CONTROL+B
modificaTextoSeleccionado(document.getElementById("caja-texto"), 'strong');
return false;
} else {
return true;
}
}
// Se cancela los eventos que se producen
function evitaEvento(evt) {
if (evt.ctrlKey) { // CONTROL+S
evt.cancelBubble = true;
// Para Firefox
if (evt.stopPropagation) {
evt.preventDefault();
}
}
}
// Obtiene el texto seleccionado y se encierra entre etiquetas
function modificaTextoSeleccionado(obj, etiqueta) {
var texto = "";
if (obj.createTextRange) { // IE
var r = document.selection.createRange();
texto = r.text;
r.text = '<'+etiqueta+'>'+texto+'</'+etiqueta+'>'
} else if (obj.setSelectionRange) { // Firefox
// Posicion inicial en el string del texto seleccionado
var ini = obj.selectionStart;
// Posicion final en el string del texto seleccionado
var fin = obj.selectionEnd;
// Obtengo el substring
obj.value = obj.value.substring(0, ini)+'<'+etiqueta+'>'+obj.value.substring(ini, fin)+'</'+etiqueta+'>'+obj.value.substring(fin);
// Selecciono lo que estaba seleccionado anteriormente más las etiquetas
obj.selectionStart = fin+5+(etiqueta.length*2);
obj.selectionEnd = fin+5+(etiqueta.length*2);
}
}
</script>
</head>
<body onkeypress="evitaEvento(event)">
<textarea onkeydown="shortcut(event)" id="caja-texto">
...
</textarea>