Ver Mensaje Individual
  #1 (permalink)  
Antiguo 27/07/2008, 16:07
Avatar de buzu
buzu
 
Fecha de Ingreso: octubre-2006
Ubicación: San Francisco, CA
Mensajes: 2.168
Antigüedad: 18 años, 2 meses
Puntos: 122
Busqueda Evitar captura de eventos simultaneos. Lo estoy haciendo bien?

Perdón por el titulo que no es muy descriptivo pero no encontré otra forma de ponerlo.

Estoy creando una nueva forma de editar las paginas web que contiene algún tipo de CMS. Como ustedes saben, ese tipo de aplicaciones te permiten editar los textos una vez han sido creados y publicados, pero yo algunas veces me encuentro en que cuando reviso el post, me doy cuenta que me falta un acento o se me fue una letra de mas o cosas así. Entonces tengo que darle al botón editar, esperar que se cargue la pagina en la que se puede editar el contenido, editar el contenido, darle a salvar y volver a ver el post publicado. Esto es muy tedioso sobre todo cuando lo único que quiero es cambiar una letra.

Para solucionar este "problema" pensé en un sistema que permitiera seleccionar la parte del texto que se quiere edita, este automáticamente se convierte en un input tipo text listo para ser editado sin tener que dar todo el viaje redondo que expliqué anteriormente. Hasta ahi todo genial. El problema esta en que para que el texto sea enviado al servidor y el cambio reflejado en la pagina, esto es, mostrar el texto tal cual sin la caja de texto, estoy usando dos eventos. Uno es el onblur de la caja de texto, así cuando la caja pierde el foco el texto editado es impreso en la pantalla. Dos, el evento onmouseup de mi elemento en el que tengo el texto. Este segundo hace dos cosas, primero cuando seleccionas un texto por primera vez convierte dicho texto en caja de texto para ser editado. Cuando presionas por segunda vez imprime el texto.

La cosa funciona bien cuando el onblur es causado por el usuario presionando TAB o por un click fuera del elemento en el que tengo el texto. Sin embargo, cuando el onblur es causado por un click dentro del elemento en el que tengo el texto, se activan los dos evento a la vez. Primero se activa el evento onblur de la caja de texto, lo cual imprime el texto como normalmente lo haría. Segundo, se activa el evento onmouseup de mi elemento en el que tengo el texto, lo cual me crea una nueva caja de texto tal como si se hubiera seleccionado otra parte de texto y eso no me gusta. Si quieren ver lo que les digo pueden probar este codigo:

Código HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8" />
	<title>seleccion</title>
	<script type="text/javascript">
	var editar = true;
	function sel(){
		if(editar == true){
			var texto = document.getElementById('seleccion');
			var inicio = window.getSelection().anchorOffset;
			var Final = window.getSelection().focusOffset;
			var textoIni = texto.innerHTML;
			textoAnterior = textoIni.substr(0, inicio);
			textoPosterior =  textoIni.substr(Final);
			var cajaValue = window.getSelection().toString();
			var textoFn = textoAnterior + "<input type='text' id='editando' value='" + cajaValue + "' size='" + cajaValue.length + "' />" + textoPosterior;
			texto.innerHTML = textoFn;
			document.getElementById('editando').focus();
			document.getElementById('editando').select();
			document.getElementById('editando').onblur = imprimeTexto;
			editar = false;
		}else if(editar == false){
			imprimeTexto();
		}
	}
	function imprimeTexto(){
		document.getElementById('seleccion').innerHTML = textoAnterior + document.getElementById('editando').value + textoPosterior;
		editar = true;
	}
	</script>
</head>
<body>
	<div id="seleccion" onmouseup="sel();">
		texto que podra o no ser seleccionado. Al seleccionar devera ser convertido en una caja de texto para que sea editado.
	
	</div>
</body>
</html> 
El codigo esta siendo provado en FF y safari. Ten en cuenta que esta en fase de desarrollo y aun no empiezo a meterme en problemas con IE. Es mas, ni lo eh probado en IE y no se si funciona. Puedes usar el probador de codigos de caricatos. Selecciona una parte del texto y veras que se convierte en caja de texto para ser editado, Edita y presiona algo alejado del texto y veras que la caja de texto desaparece y en su lugar aparece el texto seleccionado. Ahora selecciona nuevamente un poco de texo, editalo y presiona sobre alguna otra parte del texto y veras el error.

Yo lo eh solucionado de esta manera:
1.- En cuanto el texto es impreso, elimino la función asignada al evento onmouseup de mi elemento texto de tal modo que no se ejecute y no me abra otra caja de texto.
2.- Uso setTimeout para volver a asignar la función al evento onmouseup cuando creo que es seguro de modo que cuando el texto sea seleccionado nuevamente me cree la caja de texto.

Un poco difícil de explicar. Acá mi solución:

Código HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8" />
	<title>seleccion</title>
	<script type="text/javascript">
	var editar = true;
	function sel(){
		if(editar == true){
			var texto = document.getElementById('seleccion');
			var inicio = window.getSelection().anchorOffset;
			var Final = window.getSelection().focusOffset;
			var textoIni = texto.innerHTML;
			textoAnterior = textoIni.substr(0, inicio);
			textoPosterior =  textoIni.substr(Final);
			var cajaValue = window.getSelection().toString();
			var textoFn = textoAnterior + "<input type='text' id='editando' value='" + cajaValue + "' size='" + cajaValue.length + "' />" + textoPosterior;
			texto.innerHTML = textoFn;
			document.getElementById('editando').focus();
			document.getElementById('editando').select();
			document.getElementById('editando').onblur = imprimeTexto;
			editar = false;
		}
	}
	function imprimeTexto(){
		document.getElementById('seleccion').onmouseup="";
		setTimeout("document.getElementById('seleccion').onmouseup=sel",100);
		document.getElementById('seleccion').innerHTML = textoAnterior + document.getElementById('editando').value + textoPosterior;
		editar = true;
	}
	</script>
</head>
<body>
	<div id="seleccion" onmouseup="sel();">
		texto que podra o no ser seleccionado. Al seleccionar devera ser convertido en una caja de texto para que sea editado.
	
	</div>
</body>
</html> 
Nuevamente el código esta en fase de desarrollo, es un código muy rudimentario y escrito de una forma no muy recomendable pero que me sirve. Cuando esté terminada la fase rudimentaria empezaré a desarrollar con mejores practicas y todo. Lo hago así para mantener el código lo mas sencillo posible a la hora del desarrollo ya que es mas fácil de hacer el debug.

La pregunta es. Es esta la mejor forma de evitar el doble evento o hay una manera mejor de hacerlo?
__________________
twitter: @imbuzu