fadeObj.js actualizado.

November 19, 2009

Pues siguiendo las recomendaciones de mi gran amigo jseros, he actualizado fadeObj.js para implementar la simulación de los eventos onFadeStart y onFadeStep que se activan al iniciar el efecto y en cada una de las vueltas del loop respectivamente.

El código lo puedes obtener en:

http://www.p-freeweb.com/outside/javascript/fadev1.1/fadeObj1.1.js

También puedes ver un ejemplo demostrando el uso de onFadeStart y onFadeStep en:

http://www.p-freeweb.com/outside/javascript/fadev1.1/fade.html

Espero les gusten los cambios.

Espero más criticas y sugerencias.

PD. La implementación del método toggle para no tener que escoger el modo (entrada o salida) requiere un poco más de trabajo y por el momento no tengo el tiempo para implementarlo.Aun falta hacerlo cross browser.

Gracias Jseros y Panino por sus sugerencias y comentarios.

fadeObj.js –Nuevo script.

November 17, 2009

Hoy les traigo un script que estuve desarrollando durante mi tiempo libre estos dos últimos días. Aun me falta cosas por hacerle, como por ejemplo hacerlo cross browser, pero por ahora creo que es un buen ejercicio para quien lo quiera checar e incluso usar. Agradezco a mi gran amigo Panino5001 quien me ayudo a aclarar una duda que me surgió mientras codigueaba.

Checa un ejemplo de fadeObj.js

fadeObj.js

//ObjectName: fade
//Author:     Buzu.
//Varsion:    1.0
//todo:       evitar que se cancele el efecto una vez terminado.
//Bugs?:      Please report any bug to @imbuzu on twitter. use #fade1.0 #Bug

fade = {
 el : null,
 intervalo : null,
 mod : null,
 inAlph : null,
 seg : null,
 fadeF : function(e, m, s){
 //fadeF sig. fadeFunction
 //aceleramos el acceso a fade con una variable local.
 var f = fade;
 f.seg = s || 3;
 !e ? alert('No Elem') : (f.el = e);
 f.mod = m || 's';
 f.mod == 's' ? f.fadeout() : f.mod == 'e' ? f.fadein() : alert('no valid mode');
 },
 fadein : function(){
 var f = fade;
 //si se vuleve a activar el fade sobre el mismo objeto
 //no queremos que el objeto vuelva a alpha 0
 //sino que el efecto comienze con el alpha que el
 //elemento ya tiene.
 f.inAlph = f.inAlph || 0;
 f.intervalo = setInterval(
 function(){
 f.inAlph += 1/(f.seg*10);
 f.el.style.opacity = f.inAlph;
 if(f.inAlph >= 1){clearInterval(f.intervalo); f.onFadeEnd(f.el)};
 }, 100
 );
 },
 fadeout : function(){
 var f = fade;
 f.inAlph = f.inAlph || 1;
 f.intervalo = setInterval(
 function(){
 f.inAlph -= 1/(f.seg*10);
 f.el.style.opacity = f.inAlph;
 if(f.inAlph <= 0){clearInterval(f.intervalo); f.onFadeEnd(f.el);};
 },100
 );
 },
 onFadeEnd : function(){}
}

Ejemplo de uso:

window.onload = function(){
   document.getElementById('fade').onclick = function(){
      fade.onFadeEnd = function(e){
         document.getElementsByTagName('body')[0].removeChild(e);
      }
      fade.fadeF(this, 's', 2)
   }
}   

Para usar el objeto basta con llamar su método fadeF:

fade.fadeF()

Este método recibe tres parametros, el primero es el elemento al cual se le aplicará el fade, el segundo es el modo ’s’ para salida y ‘e’ para entrada y el tercero es el tiempo que durará el efecto (en segundos).

fade.fadeF(elem, 's', 5);

Solo el primer parámetro es obligatorio. Los otros son opcionales y toman como default  s y 3 respectivamente.

Al terminar el efecto, se llama al método onFadeEnd() para simular eventos:

fade.onFadeEnd = function(){
//codigo de la funcion
}

a onFadeEnd se le puede pasar un parametro el cual regresa el nodo al cual se le aplico el fade:

fade.onFadeEnd = function(e){
alert(e);
}

Para entender más el uso de fade, te invito a que revises el código fuente del ejemplo.

Espero que encuentren útil este objeto. En unos días terminare los detalles. Como siempre, estoy abierto a criticas y sugerencias.

NOTA: Este contenido es por motivos educativos e informativos solamente.

Hace un par de días se me ocurrió que posiblemente se puede acceder a las cookies de un sitio web mediante greasemonkey. Al principio pensé que un agujero de seguridad tan grande no debió pasar por enfrente de los ojos de los desarrolladores del plugin sin ser notado, así que hice una pequeña prueba la cual consiste en crear un nuevo script que sea ejecutable en todos los sitios el cual contiene solo la siguiente instrucción:

alert(document.cookie);

Es super sencillo e inofensivo. Sin embargo, al correr un sitio web te das cuenta que en efecto greasemonkey puede acceder a las cookies de cualquier sitio web. Lo que puedes hacer con esas cookies depende mucho de tu creatividad, conocimiento y por supuesto, de la cookie en sí. Por ejemplo una cosa sencilla que hice fue simplemente redireccionar el navegador a una pagina donde la cookie se manda por correo a mi bandeja de entrada. Al probar ese script pude enviarme las cookies de twitter que mi navegador almacena. Un script bien configurado y dirigido para atacar una app especifica podría causar mucho daño, o por lo menos un buen susto. Lo mas obvio que puedes hacer con esto es robar información y ganar acceso a algunas cuentas de sitios web que usan cookies de forma irresponsable.

Redireccionar no es la forma más inteligente de robarte las cookies. Pero recordemos que greasemonkey no está sujeto a las mismas normas de seguridad que javascript corriendo directamente desde un sitio web. Digo esto por que hay que recordar que ajax no está sujeto a un solo dominio, sino que puede interactuar con documentos de distintos dominios al mismo tiempo, por lo que podemos usar el mismo script que yo hice para enviar el correo, pero en lugar de redireccionar y hacer el robo de datos demasiado obvio, podemos usar ajax y hacer la transferencia totalmente transparente al usuario.

Que se puede hacer al respecto?

La verdad es muy poco probable que te pase eso, a menos que alguien esté intencionalmente haciéndolo y ahí es donde está el problema. Por ejemplo alguien puede esconder el script malicioso dentro de algún otro script. Supongamos que quiero robar las cookies de facebook de alguna persona. Solo tendría que escribir un script que fuera útil para los usuarios de facebook y distribuirlo. El script ya tiene dentro la parte que hace el truco. Puedo disfrazarla de alguna u otra manera e incluso ofuscarla. Puedo incluso hacer que el script malicioso se active solo cuando esa persona en particular lo usa y así evitarme un montón de correos en mi bandeja que en realidad no quiero. Entonces que podemos hacer?

Una de las cosas más obvias es simplemente revisar los scripts que usas, aun que claro, eso puede ser un dolor de cabeza. Puedes por ejemplo usar un editor de textos que tenga capacidad para buscar y haces una búsqueda de ‘document.cookie’ para saber cuando un script esté accediendo a las cookies de tu navegador y ver que es lo que está haciendo con ellas. Otra cosa también es usar script confiables y como siempre investigar un poco antes de instalar un script. Pero aun así, recuerda revisarlo aun si nadie reporta nada raro. Esto por que por ejemplo, yo podría descargar un script muy popular, modificarlo y redistribuirlo asegurando que mucha más gente lo va a usar que un script que yo simplemente haya creado ayer por la tarde.

PD. Probablemnte muchos quieran ver los scripts que hice para enviarme cookies a mi correo. No lo comparto por que se que ahí afuera hay muchos script kiddies que probarán todo lo que encuentren para ‘hackear’.  Además, los scripts son tan básicos que cualquiera que tenga conocimientos mínimos los puede desarrollar por si solo.

Continuando con la serie sobre ajax, veamos esta ocasión un ejemplo sencillo de la creación y el uso del objeto XMLHttpRequest, o XHR como se le conoce para abreviar. Quiero hacer notar que debido a la creciente actividad anti IE6 no quiero tratar los métodos de creación del objeto XMLHttpRequest en IE6, que generalmente requiere un try… catch. A partir de IE7, XMLHttpRequest es soportado de forma nativa, por lo que nos vamos a quedar con este método directo de acceso al objeto. Si te interesa brindar soporte para ajax en IE6, puedes buscar en la web sobre el tema.

Como una nota aparte, try… catch debería ser evitado por los problemas de desempeño que trae consigo.

Creando una nueva instancia:

Crear una nueva instancia de XHR es sumamente sencillo:


var miXHR = new XMLHttpRequest();

Con esto has creado una nueva instancia de XHR lista para ser usada, exprimida y explotada. Ahora, veamos la belleza de XHR en acción.

Para poder seguir el ejemplo, primero tienes que tener la siguiente preparación:

1)Un folder llamado ajax
2)Dentro del folder, un archivo de texto llamado texto.txt
3)Dentro del folder, un archivo HTML llamado ajax.html
4)Dentro del folder, un archivo js llamado ajax.js

El archivo de texto puede contener cualquier texto que tu quieras. El mio, por ejemplo contiene:

“Javascript doesn’t suck, you are just doing it wrong” Douglas Crockford.

Mi archivo HTML contiene tan solo el HTML necesario para ser considerado válido:


<!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>Ajax! Ah javascript ambiciosamente xtremo!!!</title>
      <script type="text/javascript" src="ajax.js"></script>
   </head>
   <body>
      <p id="ajaxPantalla"></p>
   </body>
</html>

Y mi archivo Javascript esta completamente vacío… por el momento.

Eso es todo lo que necesitas por ahora. Empecemos a trabajar en nuestro javascript:

archivo: ajax.js


window.onload = function(){
   //declaramos un event handler para el evento load de window.
}

Empezamos declarando un event handler para el evento load de window. Este nos va a permitir acceder al DOM cuando ya este totalmente cargado. El DOM, teóricamente, se termina de cargar antes de que el evento load de window sea activado, sin embargo, los métodos para poder detecta cuando el DOM ha sido cargado son, al momento de escribir este articulo, demasiado engorrosos y desde mi punto de vista no vale la pena recurrir a ellos por varias razones.
Nótese que estamos usando event handlres y no event listeners, esto es solo por comodidad, si quiere puedes usar event listeners, aun que en este ejemplo no creo que valga la pena pasar por todo el trabajo extra que eso requiere.

Continuando con nuestro ejemplo, procedamos a crear una instancia del objeto XHR y algunas variables extra que nos serán de utilidad:

archivo: ajax.js
funcion: window.onLoad


var xhr = new XMLHttpRequest();
var pantalla = document.getElementById('ajaxPantalla');
var initTime = new Date().getTime();

Empezamos por definir una nueva instancia de XMLHttpRequest, y la guardamos en una variable (xhr).
También tomamos una referencia a uno de los elementos en nuestro HTML y lo guardamos en otra variable (pantalla)
Por último, guardamos el tiempo actual en otra variable (initTime). Este ultimo paso es solo para poder ir monitorizando el tiempo que toman nuestras llamadas en ser procesadas. Al final capturaremos el tiempo de finalizado de la función y lo compararemos con el tiempo de inicio de la función para ver cuanto tiempo ha tomado el su procesamiento. Para ser mas “exactos” combendría mover la variable initTime justo al inicio, antes de xhr, de modo que el tiempo sea lo primero que se toma al iniciar la función. Sin embargo, yo lo he preferido dejar así.

Continuemos con nuestro ejemplo:

archivo: ajax.js
function: window.onload


if(xhr){
   xhr.onreadystatechange = function(){
   if(xhr.readyState == 4){
      //if(xhr.status == 200 || xhr.state == 304){
         pantalla.innerHTML = xhr.responseText;
      //}
   }else{
      //proveer mensajes para los diferentes codigos http.
   }
}
xhr.open('GET','texto.txt',true);
xhr.send(null);
}else{
   //proveer una alternativa a ajax si no está disponible.
}

Aquí es donde todo esta pasando. Primero chequeamos que efectivamente xhr esté disponible, de no ser así, proveemos un método alternativo:


if(xhr){
   ...
}else{
   //proveer una alternativa a ajax si no esta disponible
}

En este ejemplo no vamos a hablar sobre alternativas, eso lo dejaremos para ejemplos mas adelante.

Si el primer if nos da true, entonces sabemos que xhr esta disponible, por lo que es seguro continuar.


xhr.onreadystatechange = function(){
   if(xhr.readyState == 4){
      //if(xhr.status == 200 || xhr.state == 304){
         pantalla.innerHTML = xhr.responseText;
      //}else{
         //proveer mensajes para los diferentes codigos http.
      //}
   }
}
xhr.open('GET','texto.txt',true);
xhr.send(null);

Lo primero que hacemos una vez determinado que el objeto xhr está disponible, es asignar una función a su evento readystatechange. Este evento se genera cada vez que el estado de la petición cambia. En esta ocasión no hablaremos de los diferentes estados de la petición, eso lo dejaremos para el siguiente artículo. Por ahora basta con que sepas que el cuarto estado es cuando la petición ha sido exitosa y nos ha regresado los resultados.

En un ejemplo real, o si estas corriendo los ejemplos en un localhost, puedes chequear el estado (status) de la respuesta (response). Si sabes algo de los códigos http, sabrás que 200 significa OK y 304 significa no modificado. En nuestro ejemplo chequeamos si el status de la respuesta es 200 o 304, lo que significa que el documento está disponible, de no ser así, enviamos mensajes diferentes dependiendo el código http de la respuesta. En este caso no hemos incluido esos mensajes, pero implementarlos no es difícil.

Una vez determinado que el status de la respuesta es 200 o 304, podemos imprimir el contenido de nuestro archivo txt a nuestra pantalla, para eso usamos innerHTML para asignar a pantalla el texto regresado por xhr.

xhr tiene dos diferentes tipos de respuesta: responseText y responseXML. Dependiendo de lo que estés pidiendo al servidor querrás usar uno u otro. La mayor parte del tiempo estarás usando responseText, por lo que en nuestros ejemplos nos mantendremos especialmente ligados a el.

Las ultimas dos lineas son las que en realidad hacen la petición:

xhr.open() toma mínimo dos parámetros, el método (GET o POST entre otros) y la url del recurso que queremos pedir (en nuestro caso ‘texto.txt’). El tercer parámetro determina si la petición es sincrónica o asíncrona. En nuestro caso, true, le dice al navegador que la petición debe ser asíncrona. En un futuro hablare de las diferencias entre peticiones sincrónicas y asíncronas, por el momento, basta con saber que la mayor parte del tiempo usaras true como tercer parámetro.

Como una nota aparte, el tercer parámetro no debería ser nunca false por problemas de desempeño.

xhr.open() también recibe otros dos parámetros (usuario y clave) para autentificación básica. Estos los usas cuando un sitio te pide una clave y contraseña. Por ejemplo, si vas a:

http://twitter.com/statuses/user_timeline.xml

te darás cuenta que el navegador te pide una clave y contraseña. Si estuvieras haciendo una petición vía ajax a una página similar, usarías los dos últimos parámetros para especificar tu usuario y contraseña. Toma en cuenta que esto no es recomendable ya que ajax es javascript y los archivos javascript pueden ser fácilmente vistos. Su uso puede ser para, por ejemplo, autentificar usuarios usando ajax donde tanto usuario como clave sean provistos por el usuario y no “hard codded” en el javascript.

xhr.send() sirve para enviar datos. En nuestro caso no estamos enviando nada, por lo que usamos null, habrá ocasiones cuando quieras enviar datos, por ejemplo para un sitio que requiere opciones como un índice de temas en un blog. En ejemplos futuros veremos como se usa send() para enviar datos. Por ahora, no es necesario.

Este ha sido un ejemplo sencillo del uso de ajax. En futuros artículos veremos ejemplos mas complejos y útiles. Habrás notado que en este ejemplo todo sucede cuando se carga la pagina, lo cual realmente no tiene sentido. EL objetivo es poder hacer las peticiones como respuesta al input del usuario ya sea hacer click en un enlace, un botón, o simplemente enviar un formulario.

Aquí esta el código completo, notaras que he agregado algunas variables y un par de lineas para medir el tiempo que tarda (en milisegundos) nuestra petición en ejecutarse. Es simplemente para poder ir manteniendo en mente un poco el desempeño de nuestras funciones.

archivo: ajax.js (completo):


window.onload = function(){
   //declaramos un event handler para el evento load de window.
   var xhr = new XMLHttpRequest();
   var pantalla = document.getElementById('ajaxPantalla');
   var initTime = new Date().getTime();
   var finTime = null;
   var totTime = null;

   if(xhr){
      xhr.onreadystatechange = function(){
         if(xhr.readyState == 4){
            //if(xhr.status == 200 || xhr.state == 304){
               pantalla.innerHTML = xhr.responseText;
               finTime = new Date().getTime();
               totTime = finTime - initTime;
               alert(totTime + 'milisegundos');
            //}
         }else{
            //proveer mensajes para los diferentes codigos http.
         }
      }
      xhr.open('GET','texto.txt',true);
      xhr.send(null);
   }else{
      //proveer una alternativa a ajax si no esta disponible.
   }
}

Espero verlos en la siguiente entrega.

Ajax: Introducción

September 2, 2009

Ajax es una tecnología que muchos consideran relativamente nueva. Para mí, ajax ya no tiene nada de nuevo. Su época de fama parece haber pasado, y gracias a Dios su época de abuso también, no así su tiempo de uso. Ajax sigue representando un tremendo potencial, aun que desgraciadamente son pocos los que le han sabido sacar provecho, la mayoría solo lo han abusado y jugado con él, como quien abusa de cualquier juguete. Desgraciadamente, el tremendo poder que ajax representa, se ha salido del control en las manos de unos cuantos script kiddies que no han sabido usarlo propiamente.

En esta serie voy a tratar de enseñar, no solo ajax, sino su uso correcto en base a mi experiencia como desarrollador y sobre todo como usuario consiente del verdadero potencial que la web puede alcanzar con un arma tan poderosa como ajax en nuestra bolsa de herramientas.

Empecemos por definir lo que es ajax. Para poder comprender ajax y usarlo propiamente, primero hay que entender que ajax es solo una combinación de diferentes tecnologías existentes, todas ellas unidas por un solo objeto. Ese objeto se llama XMLHttpRequest. Fue introducido por Microsoft como componente de Active X, posteriormente fue adoptado por mozilla y en la actualidad se encuentra en desarrollo una especificación por parte de la W3C. Las diferentes tecnologías que se mantiene unidas por este objeto varían dependiendo el proyecto y las preferencias del desarrollador, pero comúnmente se usan solo dos: Javascript y (X)HTML. Sin embargo, en esta ensalada de tecnologías pueden entrar en juego algunos otros componentes como puede ser PHP, XML, texto plano etc.

Mucha gente confunde ajax con DOM scripting o con el antiguo DHTML. Estos son totalmente diferentes, y por ningún motivo deben confundirse ya que eso puede traer problemas al momento de tratar de separar uno del otro para poder crear una metodología de trabajo mucho más eficiente. Por ejemplo, un buen programador querrá mantener sus mecanismos relacionados con ajax aparte de los relacionados con DOM scripting de modo que los problemas que pueda presentar puedan ser divididos a su vez en problemas más pequeños y más fáciles de solucionar. Si el programador no sabe distinguir entre ajax y DOM scripting, lo más probable es que termine mezclando ambos procesos haciendo imposible dividir el problema de la forma más eficiente y, por ende, causando que el desarrollo sea más difícil. La pregunta es, entonces, como distinguir entre uno y otro?

Ajax tiene solo un objetivo. Su principal funcionalidad está muy bien definida y teóricamente debe ser completamente sencillo poder identificar en donde empieza y termina su área de trabajo. Ajax tiene como objetivo la comunicación con el servidor de forma asíncrona. Uno de los típicos abuso de ajax es usarlo para acarrear datos del servidor al navegador por el simple hecho de no querer recargar la página, entonces terminamos con sitios que recargan todo, menos el menú, cada vez que se hace un click. El trabajo de ajax no es simplemente acarrear datos de un lado a otro, sino poder interactuar con el servidor en tiempo de ejecución y delegar tareas que han de ser ejecutadas, esperar por la respuesta y luengo entonces traer la respuesta de regreso al cliente. Solo cuando logramos entender lo que esto significa, hemos logrado entender ajax.

Para evitar su abuso, hay que considerar cada una de las tecnologías que están en juego, sus limitaciones, su desventajas y su grado de inaccesibilidad. Así también hay que poner en la balanza los beneficios que su uso puede traer y los problemas que puede causar, pero sobre todo, hay que proveer siempre de una alternativa para aquellos que por una u otra razón han de navegar si ajax.

A lo largo de esta serie vamos a hablar de formas para resolver distintos problemas. Vamos a analizar diferentes situaciones en la que podemos usar ajax y sobre todo, vamos a desarrollar una metodología de trabajo que nos permita desarrollar pensando siempre en accesibilidad para todos. Esta ha sido solo la introducción, espero poder verlos y sobre todo leer sus comentarios a lo largo de esta serie.

Next time:
La siguiente vez empezaremos con el uso de ajax y veremos algunos ejemplos prácticos de su potencial.

Super Menú V0.002

July 10, 2009

He estado trabajando en un script para poder crear menús desplegables a partir de arrays. Ayer terminé lo que yo llamo la versión 0.002 de dicho script y quisiera compartirla con ustedes. Me gustaría aclarar que el propósito de compartirla no es distribuirla, por lo menos no todavía. El propósito en compartirla es más bien en cierta forma liberar el código y permitir que otros usuarios aprendan de él, pero también abrir un flujo de información a través del cual se estén haciendo sugerencias sobre lo que habría que mejorar, o cambiar en el script para lograr una mejora en el desempeño. También cabe aclarar que en proyectos abiertos al publico en general, como en sitios web, no es recomendable su uso ya que es un asesino de todo intento de accesibilidad. Esto por la simple razón de que Javascript es absolutamente necesario para poder crear el menú. Por tal motivo, recomiendo que si se usa, sea solo en ambientes que tenemos ‘controlados’ o en los que sabemos que los usuarios necesariamente tendrán javascript disponible y activado, por ejemplo, en una aplicación AIR, en el área administrativa de un sitio a la que sabemos que se accede con javascript disponible y activado, a apps locales que se usan con dispositivos que tienes javascript disponible y activado y situaciones similares.

La lógica detrás del script es muy sencilla. Si sigues regularmente el blog, habrás notado que me gusta hacer scripts sencillos y en cierta forma demostrar que los scripts no tiene por que alcanzar un nivel de complejidad que resulte confuso incluso para el autor de script. El script consiste, por el momento, de un constructor y un objeto. El constructor es una función llamada Desplegable. El trabajo de esta función es crear una serie de listas (elementos ul) anidadas tomando como base un array el cual se le pasa como primer parámetro. La función por el momento toma tres parámetros, dos de los cuales son opcionales. Como la función es un constructor y tratada como tal, la llamada no puede ser directa, hay que crear una instancia del constructor, por lo que una llamada a la función se vería más o menos así:

var miMenu = new Desplegable(estructura, direccion, contenedor);

En donde:

estructura: es el array sobre el cual se basa el menú.

direccion:por ahora toma solo un valor, ‘vertical’,  y sirve para especificar la dirección en la que el menú es creado.

contenedor: Es el id del elemento en el cual queremos que se cree nuestro menú.

de modo que si quiero crear un menú y que este sea agregado dentro de un div con id=’cabecera’, la llamada sería la siguiente:

var miMenu = new Desplegable(estructura, 'vertical', 'cabecera');

Notar que el último parámetro es el id y no una referencia al elemento en el cual queremos que se agregue el menú. Pasar una referencia del tipo:

var cabecera = document.getElementById('cabecera');
var miMenu = new Desplegable(estructura, direccion, cabecera);

Daría un resultado inesperado que podría causar destrozos en tu proyecto.

El único parámetro que por el momento es obligatorio es el primero, el cual pasa la estructura del array que queremos tomar como base para crear las listas anidadas. El segundo parámetro, si no se especifica, toma como por defecto el valor ‘vertical’. Recordar que este parámetro por ahora solo puede tomar el valor ‘vertical’. El tercer parámetro, si no se especifica, toma como valor por defecto el elemento body (etiqueta <body>). Es poco recomendable que no se especifique este parámetro ya que puede causar efectos inesperados como poner el menú hasta el final de la página, después incluso del pié de página.

El otro componente es un objeto llamado sM. Este se encarga de dos cosas:

1)Carga el CSS para el menú
2)Controla el plegado y desplegado de los sub-menús.

Este elemento es reciclado, es decir, ya lo tenía entre mis curiosidades. Cabe aclarar que este objeto no es de mi propia autoría, fue más bien creado en uno de los capítulos de DHTML utopia. El propósito al incluir este objeto fue demostrar que es sencillo crear nuestro propio objeto para controlar el plegado y desplegado de los menús de la forma en que queramos. Siempre y cuando nos aseguremos de que dicho objeto llame una función de Desplegable llamada aggCSS(), la cual agrega el CSS al menú.

La razón del porque aggCSS es llamada por el objeto que controla el plegado y desplegado de los sub-menús, es por que si en determinado momento quisiéramos crear nuestro propio objeto para controlar el plegado y desplegado de los menús interiores, sería útil llamar solo a la función Desplegable, analizar el código que genera y ver el árbol que genera. (El CSS nos impediría ver ese aábol.) Poder ver el árbol que genera es una gran ventaja ya que con simplemente ver la estructura de las listas anidadas te puedes dar una idea sobre como controlarlas.

Bueno, sin más, veamos como se hace una llamada real al menú. Como lo que me interesa es simplemente demostrar la creación del array, no tomaré en cuenta los dos últimos parámetros, dejándolos que tomen sus valores por defecto.

<!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>Untitled</title>
 <script type="text/javascript" src="sM.js">

 </script>
</head>
<body>
<script type="text/javascript">

 estructura = [
 'acerca de->about.html',
 'bio->bio.html',
 [
 'proyectos',
 [
 'CSS',
 'menus->menuscss.html',
 'galerias->galeriascss.html',
 'layouts->layoutscss.html'
 ],
 [
 'javascript',
 'menus->menusjs.html',
 'galerias->galeriasjs.html',
 'animaciones->animacionesjs.html'
 ],
 'php->proyectosphp.html'
 ],
 'contacto->contacto.html',
 [
 'sitios amigos',
 'jseros->http://www.jseros.com/',
 'panino5001->http://www.disegnocentell.com.ar/',
 'I\'m Buzu->http://imbuzu.wordpress.com/'
 ]
 ]
 var miMenu = new Desplegable(estructura);
 sM.menuRef = miMenu;
 sM.init();
</script>

</body>
</html>

Algunas cosas a notar:

El array es un array multidimencional donde cada array anidado representa un ul anidado.

Para especifcar la url a la que apunta el elemento del menú, se pone “->” seguido directamente de la url a la que apunta dicho elemento.

notar sM.menuRef = miMenu. Aquí lo que estamos haciendo es pasandole a sM una referencia al menú para que sepa que aggCSS activar.

Notar la llamada a sM.init().

Creo que el código se explica por si solo. Puedes ver un ejemplo en vivo en:

http://www.p-freeweb.com/outside/javascript/scripts/supermenu/v0_002/sMV0_002Demo.html

También puedes ver el Javascript en:

http://www.p-freeweb.com/outside/javascript/scripts/supermenu/v0_002/sMv0_002.js

Nota: El menú aun no es ni versión 1, por lo que hay muchas cosas que se pueden mejorar aun, espero sus comentarios. El menú ha sido provado en FF 3.5. Tomando en cuenta que su uso no es recomendable para proyectos públicos, soporte para IE no es una prioridad.

Hace ya un buen tiempo que dejé inconclusa una serie de artículos sobre Programación Orientada a Objetos en Javascript. Bueno, aquí traigo esta última entrega, y aun que en la anterior prometí que en esta entrega haríamos una librería, creo que eso quedará más bien fuera del contexto ya que dicha librería no usa mucho los conceptos de POO de los que hemos estado hablando. Sin embargo, ya abriré otra serie para ir creando dicha librería. Más que por el gusto de crear la librería, por el gusto de tocar algunos temas en Js que no se tocan mucho.  Bueno, pero eso será en un futuro. Por ahora me limitaré a hablar sobre cuatro tipos de métodos que pueden ser usados especialmente cuando estamos programando basados en constructores do objetos.

Dependiendo de lo que queramos lograr y de la accesibilidad que queramos darle a los métodos de nuestros objetos podemos usar uno de cuatro tipos de métodos: públicos, privado, privilegiados y estáticos. Empecemos analizando de adentro a afuera, es decir, con métodos privados.

Métodos privados:

Lo métodos privados no son accesibles desde fuera del objeto. Como su nombre lo dice, estos métodos son privados. Nos interesa usar métodos privados por ejemplo cuando queremos darle a nuestro objeto una funcionalidad que no nos interesa o que no nos conviene que sea posible acceder desde fuera del objeto. Consideremos el siguiente ejemplo:

Nota: también hay propiedades privadas y son más comunes que los métodos privados.

function miObj(){
    var nombre =  'Nombre Privado';//propiedad privada
   function privada(){//Método privado
       alert('función privada');
    }//fin del método privado
}

En este caso, el método privada() no puede ser accedido desde ningún lugar fuera de miObj();, es decir que:

var obj = new miObj();
obj.privada();//tira un error.

No es valido por que no hay nada que ligue privada() con el exterior. Pero entonces por que querías un método que no se puede llamar desde ningún lado? Una de las razones es para mantenerte organizado y seguir una de las mejores prácticas de la programación. Me refiero a que cada función tiene que tener solo un trabajo. Por ejemplo:

function miObj(){
    function mostrarOpciones(){
       //Codigo para mostrar opciones
    }
    function crearCanvas(){
       //Código para crear canvas
    }
    mostrarOpciones();
    crearCanvas();
}

Esas dos funciones se ejecutan al mismo tiempo por lo que daría igual hacer lo siguiente:

function mi Obj(){
    //Código para mostrar opciones
    //Código para crear canvas
}

Sin embargo, es mucho más fácil y legible una función que tiene un solo objetivo ya que 1) todo el código está relacionado entre sí, y 2) hay menos lineas de código. Además de que al haber más funciones hay más probabilidades de que un error sea identificado con mayor precisión.

Métodos privilegiados.

Hace un rato vimos los métodos privados. Pero si tienes ojo de debugger, seguro que te diste cuenta que también hemos puesto una propiedad privada (nombre). Al igual que el método privado, la propiedad privada no puede ser recuperada desde fuera del objeto. Es decir que si hace:

alert(obj.nombre);

te va a dar como resultado una alerta que dice undefined. No es un error del navegador. Es simplemente que no tienes los permisos necesarios para acceder a esa  propiedad, porque está “encerrada” dentro de las fronteras de miObj(). El uso de propiedades privadas es muy útil cuando quieres establecer valores que no quieres que sean modificados desde fuera del objeto. Por ejemplo, una velocidad que quieres que se mantenga constante cuando realizas una animación, o algún valor que no quieres que sea modificado. Considera el siguiente ejemplo:

function animador(){
    var velocidad =  .1;
}

var animcion = new animador();

En este caso hemos creado un constructor (animador()) que contiene una propiedad privada (velocidad). Esta propiedad la hemos puesto privada por que no queremos que la velocidad de animador pueda ser cambiada usando:

animacion.velocidad = .5;

ya que probablemente eso causaría resultados inesperados.

Pero entonces si no se puede acceder a la propiedad, para que nos sirve? Bueno, en realidad para nada, por lo  que es necesario encontrar una forma de poder acceder a la propiedad. Para eso están los método privilegiados.

Como su nombre lo indica, estos métodos tiene privilegios especiales. Piensa en ellos como si tuvieran su propia puerta para entrar y salid del contexto de su contenedor, en este caso miOBj();

Volvamos a nuestro ejemplo el cual hasta ahora va así:

function miObj(){
    var nombre =  'Nombre Privado';//propiedad privada
    function privada(){//Método privado
       alert('función privada');
    }//fin del método privado
}

var obj = new miObj();

Hagamos uno cambios en miObj():

function miObj(){
var nombre =  ‘Nombre Privado’;//propiedad privada
function privada(){//Método privado
alert(‘función privada’);
}//fin del método privado
//agregamos método privilegiado
this.obtenerNombrePrivado = function(){
return nombre
}
}

El método obtenerNombrePrivado() es privilegiado, lo cual quiere decir que puede acceder a los métodos y propiedades privados declarados dentro de miObjt(). Esto tiene que ver con lo que se conoce como scope. Trataré de explicarlo:

Al ser declarada dentro de miObj(), otenerNombrePrivado() tiene acceso a las variables locales de miObj(), en nuestro caso solo tenemos una variable local (nombre). Esto por que al ejecutarse obtenerNombrePrivado() se ejecuta dentro del contexto y las fronteras de miObj() en donde nombre si existe.

Ahora podemos acceder a nuestra propiedad privada (nombre) sin ningún problema, pero sigue siendo imposible cambiarla:

function miObj(){
    var nombre =  'Nombre Privado';//propiedad privada
    function privada(){//Método privado
       alert('función privada');
    }//fin del método privado
    //agregamos método privilegiado
    this.obtenerNombrePrivado = function(){
       return nombre
    }
}
var obj = newObj();
alert(obj.obtenerNombrePrivado());//regresa Nombre Privado

Cabe aclarar que los métodos privilegiados siguen siendo métodos públicos, razón por la cual se pueden acceder desde fuera del objeto.

Métodos Públicos

Los métodos públicos están disponibles desde fuera del objeto. Es decir que son accesibles. Su uso es prácticamente para poder brindar formas de manipular el objeto o de acceder a sus funciones y ejecutar sus comandos. He visto a muchos que hacen lo siguiente para declarar método públicos:

function otroObj(){
    this.publico1 = function(){
       //código de publico1
    }
    this.publico2 = function(){
       //código de publico2
    }
    this.publico3 = function(){
       //código de publico3
    }
    this.publico4 = function(){
       //código de publico4
    }
}

Esto, aun que parezca correcto, es una forma ineficaz de hacerlo. Tener en cuenta que estos no son métodos privilegiados, es decir que no tiene que acceder a ninguna propiedad privada del objeto.

La razón por la que ésta forma de hacer las cosas no es la mejor es por que con cada copia que hagamos de nuestro objeto, estamos “clonando” todas esa funciones y podemos llegar a sobre cargar la memoria. Una de las grandes bondades de Js, es que es un lenguaje basado en prototipos.

Que es un prototipo?
Un prototipo es la forma en que Js nos brinda la oportunidad de extender un objeto. Es decir, a través de un prototipo podemos agregar funcionalidad a un objeto que de otro modo sería poco posible. Al inicio, la palabra prototipo puede sonar un poco intimidatoria. Sin embargo, no hay nada del otro mundo envuelto en esta palabra.

Creando métodos públicos usando prototipos
Para crear un método público de una forma más eficaz, es necesario usar el prototipo de nuestro objeto:

otroObj.prototype.publico1 = function(){
    //código de público 1
}

De esta manera evitamos clonar publico1 cada vez que creamos una nueva copia de otroObj ya que el prototipo no se clona. El prototipo más bien permanece al alcance de los objetos creados a partir del objeto base (otroObj) pero no está contenido dentro de ellos. Piensa en el prototipo como una caja de herramientas que es compartida por un numero determinado de carpinteros. Sin importar cuantos carpinteros agregues, siempre va a seguir habiendo una caja de herramientas y todos los carpinteros tendrán acceso a ella.

Una vez que actualices el prototipo de un objeto, todos los objetos creados a partir de dicho objeto tendrán acceso al prototipo actualizado y no al prototipo existente al momento de ser creados. Volviendo a nuestra analogía con los carpinteros, supongamos que al principio ponemos un carpinteros y una caja de herramientas. La caja de herramientas contiene un serrucho y un martillo. nuestro carpintero puede hacer uso de cualquiera de ellos. Después ponemos otro carpintero, quien a su vez puede hacer uso tanto del martillo como del serrucho. Después “actualizamos” la caja de herramientas y agregamos una lijadora. Ambos carpinteros siguen teniendo acceso a las tres herramientas aun que la caja solo tuviera dos herramientas cuando los carpinteros fueron agregados. Esa es mas o menos la forma en que trabajan los prototipos.

Una forma de hacer uso del prototipo de un objeto es mediante OLN.

otroObj.prototype = {
    publico1: function(){
       //...
    },
    publico2: function(){
      //...
    }
}

De esa manera podemos organizar los prototipos de una mejor manera y ahorramos algunos cuantos caracteres.

Métodos estáticos

Por último hablemos de uno de los tipos de métodos menos comunes, los métodos estáticos. Los métodos estáticos no son de ayuda en la mayoría de los casos. La razón de esto es por que no pueden ser usados más que por el objeto base.  Estos métodos son más bien de utilidad cuando estamos creando un objeto y no un constructor. Ejemplo:

var obj = new Object();

obj.método1 = fucntion(){...}

pero también se pueden usar cuando se están creando constructores:

function miObj(){
    var nombre =  'Nombre Privado';//propiedad privada
    function privada(){//Método privado
       alert('función privada');
    }//fin del método privado
    //agregamos método privilegiado
    this.obtenerNombrePrivado = function(){
       return nombre
    }
}
miObj.estatico = function(){
 alert('estatico');
}
var obj = newObj();

miObj.estatico();// da una alerta: estatico

obj.estatico();// Causa erro: obj.estatico() is not a function

A diferencia del ejemplo que vimos anteriormente en el que con cada copia del objeto clonabamos todos sus métodos públicos, los métodos estáticos no se copian y pertenecen solo al objeto base. Por lo que en nuestro ejemplo, obj.estatico() nos tira un error ya que no hay ninguna función que se llame estatico() relacionada con obj. Por el contrario, miObj.estatico() funciona perfectamente.

Esto nos puede ser útil en algunas ocasiones, especialmente cuando queremos extender un objeto sin afectar a todos los demás que hayan sido creados a partir del mismo objeto.

Hay más cosas que decir en cuanto a los Métodos de un objeto y todavía se nos a quedado en el teclado conceptos como herencia en Js, pero por ahora me despido esperando que haya sido una buena lectura.

Pues hace ya un rato desde el último articulo. Hoy me he inspirado y he hecho algunas pruebas de funciones en Javascript. Básicamente de diferentes forma de crear funciones, he aquí mis resultados no tan científicos y no tan estudiados ^-^.

Formas de crear funciones:

Hay diferentes formas de crear funciones, y dependiendo de lo que quieras hacer quizá quieras usar una o otra. Aun que generalmente no importa como declares tu función, nada mal hace el saber.

Lo más conocido:

La forma más sencilla y conocida de declarar funciones es la siguiente:

function alertar(){
     alert('ups!');
}

De esta manera hemos creado una función, y para llamarla solo necesitamos hacer referencia a ella:

alertar();

Así que, que hay de especial con esta forma de declarar funciones? Probablemente no mucho, excepto claro que te deja llamar a la función aún antes de que esta sea declarada:

alertar();
function alertar(){
   alert('ups!');
}

Pero probablemente eso ya lo sabias. Lo que es más, probablemente pensabas que es la forma en que todas las funciones reaccionan. Sin embargo no es así.

Otro metodo:

La siguiente es otra forma también muy conocida de crear funciones, pero que se comporta de forma un poco diferente a la forma que hemos visto anteriormente.

Se puede asignar una función a una variable:

var alertar = function(){
   alert('ups!');
}

Solo que a diferencia de la forma que hemos visto anteriormente, esta no te deja llamar funciones que no hayan sido declaradas previamente. Es decir que lo siguiente:

alertar();
var alertar = fucntion(){
   alert('ups!');
}

nos tira un error. La razón de esto tienes que ver con la declaración de las variables, pero en este post no voy a entrar en detalles con respecto a ese asunto. Así que si esta forma de declarar funciones tiene ese “problema” por que querríamos usarla? bueno, hay momentos en los que esa es la forma en que queremos declarar una función. Por ejemplo, cuando agregamos métodos a un objeto como veremos más adelante, o cuando queremos crear funciones auto ejecutables.

Funciones auto ejecutables

También se pueden crear funciones que se auto ejecutan al momento de ser leídas.

var alertar = function(){
   alert('ups!');
}();

Los paréntesis al final de la función le dicen al motor de javascript que la función debe ser ejecutada tan pronto sea leída. Esto probablemente no parezca útil al principio ya que la función deja de existir al momento en que se ejecuta, pero hay ocasiones en las que eso es lo que queremos hacer. Para comprobar esa temporalidad de la función puedes intentar lo siguiente:

var alertar = function(){
   alert('ups!');
}();
alertar();

Para poder crear funciones auto ejecutables es necesario usar la sintaxis:

var variable = function(){}

ya que si queremos usar la sintaxis del primer ejemplo (function funcionName(){}) obtenemos un error. Esta es una de las ocasiones en que queremos usar esta sintaxis que parece tener una desventaja al no dejarnos llamar a las funciones antes de que sean declaradas.

Pero ya en serio, por que queríamos hacer una función que se va a perder en el limbo tan pronto sea leída, lo que quiere decir que no la podemos volver a llamar en ningún otro momento? Una de las utilidades que yo le he encontrado es para solucionar problemas con el ámbito de las variables mediante closures, pero ese es otro tema. Lo único que voy a dejar es el siguiente ejemplo:

var alertar = function(){
   return function(){
      alert('ups!');
   }
}();
alertar();

De esta manera la función auto ejecutable puede ser llamada en cualquier momento, aun que al ejecutarse al inicio, cuando es leída, no ejecutará el alert ya que esta en la función que es regresada al ejecutarse la función exterior. Este es otro ejemplo que se ve sin sentido, pero sin embargo, es muy útil en ciertas ocasiones.

Funciones anónimas

También se pueden crear funciones anónimas de la siguiente manera:

(function(){
   alert('ups!');
});

Solo que como esta función es anónima no hay forma de llamarla después, por lo que la única forma de poder usarla es haciéndola auto ejecutable:

(function(){
   alert('ups!');
})();

Esta sintaxis es especialmente útil cuando queremos crear pseudo namespaces para evitar problemas de compatibilidad cuando usamos diferentes librerías. Aún que no es la única forma de lograr esto, si es una forma elegante y que a más de un novato lo hará verse como un “pro”.

El constructor

Por último veamos la forma menos recomendable, pero probablemente más poderosa, de crear funciones. Esta función es usando el operador new para crear un objeto Function. Esta es una  bestia peligrosa y recomiendo que sea evadida, pero de cualquier modo vamos a tocarla por el simple gusto de hablar de ella.

Para declarar una función de esta manera se hace de la siguiente forma:

var alertar = new Function('arg1','arg2','alert("ups1");');

en donde arg1 y arg2 son los argumentos que le queramos pasar a la función. Se pueden pasar tantos como se desee. El motor de Js sabe que el último set de comillas es el que contiene las instrucciones a ejecutar. Esta sintaxis es especialmente útil cuando se quieren crear funciones al vuelo o dar la oportunidad al usuario de crear sus propias funciones. Como dije, esto es una bestia y es mejor alejarse de ella a menos que sepas lo que estas haciendo y no tengas otra opción.

Ys estaré escribiendo un poco más sobre funciones ya que hay un par de cosas que se quedan pegadas al teclado por el momento. Espero sus comentarios.

Actualización: ejemplo en funcionamiento.

Hace ya algunos días @vochomaster me sugirió explicar como hacer un slideshow y me puso como ejemplo uno hecho en flash. A el no le gusta flash, por lo que me pidió que explicara como hacerlo pero en Javascript.

Hace un rato terminé el slide show, aun que la verdad no me convence ya que he usado OLN (Object Literal Notation) para construir el objeto que le da vida al slideshow. @jseros me sugiere que use constructores en lugar de OLN lo cual es una idea genial, y que ya había probado. De hecho el primer prototipo que hice del slideshow estaba basado en constructores y una mezcla entre métodos privados, privilegiados y públicos, pero no me gusto el rumbo que estaba tomando ni la complejidad que estava agarrando. Además, la razón por la que usar constructores es una buena idea, es por que eso nos agrega un punto en reusabilidad, pero al final eh decidido que rehusabilidad no es algo que quiero lograr en este caso debido al consumo de recursos que el efecto genera.

El efecto usa “fuerza bruta” para funcionar y si se abusa puede terminar colgando el navegador. Por supuesto que esto puede mejorarse e implementar mejores métodos para animación en lugar de un simple (y flojo) temporizador, pero este efecto, junto con el de alertas tipo twitter son simplemente propuestas aventadas al aire para servir como inspiración o modelo base de otros proyectos, o simplemente como ejercicios para intermedios en el uso de Js.

Bueno, sin más este es el código:

<!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="en" lang="en">
<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 <title>..::**SlideShow**::..</title>
 <script type="text/javascript">
 var ss = {
 body : null,
 trueStop: false,
 intervalo : null,
 velocidad : 1,
 playing : true,
 init: function(){
 ss.body = document.getElementsByTagName('body')[0];
 if(ss.compatible()){
 ss.crearMarco();
 }else{
 alert('Tu navegador sucks!');
 }
 },
 compatible : function(){
 if(document.getElementById && document.getElementsByTagName && document.createElement && document.appendChild && document.removeChild){
 if(ss.body.setAttribute){
 return true;
 }else{
 return false;
 }
 }else{
 return false;
 }
 },
 crearMarco : function(){
 var marco = document.createElement('img');
 marco.setAttribute('src', 'FrameFotografico.gif');
 marco.style.position = 'absolute';
 marco.style.top = document.getElementById('ss').offsetTop + 'px';
 marco.style.left = document.getElementById('ss').offsetLeft + 'px';
 marco.onmouseover = ss.stopSS;
 marco.onmouseout = function(){if(!ss.trueStop){ss.playSS()} };
 ss.body.appendChild(marco);
 ss.crearControles();
 },
 crearControles : function(){
 var controles = document.createElement('div');
 var menos = document.createElement('img');
 var stop = document.createElement('img');
 var mas = document.createElement('img');
 menos.setAttribute('src', 'icon-menos-silver.gif');
 stop.setAttribute('src', 'icon-stop-silver.gif');
 mas.setAttribute('src', 'icon-mas-silver.gif');
 menos.onclick = ss.desacelera;
 stop.onclick = ss.playPause;
 mas.onclick = ss.acelera;

 controles.appendChild(menos);
 controles.appendChild(stop);
 controles.appendChild(mas);
 ss.body.appendChild(controles);

 ss.prepararSS();
 },
 playPause : function(){
 if(ss.playing){
 ss.stopSS();
 this.src = 'icon-play-silver.gif';
 ss.trueStop = true;
 }else{
 ss.playSS();
 this.src = 'icon-stop-silver.gif';
 ss.trueStop = false;
 }
 },
 desacelera : function(){
 if(ss.velocidad > 1){
 ss.velocidad --;
 }
 },
 acelera : function(){
 ss.velocidad++;
 },
 prepararSS : function(){
 document.getElementById('ss').style.overflow = 'hidden';
 document.getElementById('ss').style.position = 'relative';
 ss.lis = document.getElementById('ss').getElementsByTagName('li');
 for(i=0; ss.lis[i]; i++){
 ss.lis[i].style.position = 'absolute';
 ss.lis[i].style.left = i*400 + 'px';
 }
 ss.playSS();
 },
 playSS : function(){
 ss.intervalo = setInterval(function(){
 ss.lis[0].style.left = parseInt(ss.lis[0].style.left) - ss.velocidad +'px';
 for(i=1; ss.lis[i]; i++){
 ss.lis[i].style.left = i*400 + (parseInt(ss.lis[0].style.left)) + 'px';
 }
 if(parseInt(ss.lis[0].style.left) <= -405){
 lisActual = ss.lis[0];
 document.getElementById('ss').removeChild(ss.lis[0]);
 document.getElementById('ss').appendChild(lisActual);
 }
 }, 100);
 ss.playing = true;
 },
 stopSS : function(){
 clearInterval(ss.intervalo);
 ss.playing = false;
 }
 }

 window.onload = function(){
 ss.init();
 }

 </script>
 <style type="text/css">
 ul
 {
 height: 250px;
 width: 400px;
 overflow: scroll;
 padding: 0;
 }
 ul li{
 width: 400px;
 height: 250px;
 float: left;
 border:1px #000 solid;
 list-style-type: none;
 }
 </style>
</head>
<body>
 <ul id="ss">
 <li><br /><br />texto1</li>
 <li><br /><br />texto2</li>
 <li><br /><br />texto3</li>
 <li><br /><br />texto4</li>
 <li><br /><br />texto5</li>
 </ul>
</body>
</html>

Para usar el efecto solo basta con crear una lista desordenada (<ul>) y darle como id el valor “ss”. Después llamar ss.init() al cargar la página.

No me tomo el tiempo para explicar lo que el javascript hace por que creo que es totalmente lineal y entendible, pero si alguien tiene dudas solo pregunteme, o si considera que es necesaria una explicación de código, diganme.

Notar que si el navegador no soporta los métodos necesarios para que el slideshow funcione, el efecto se degradará mostrando un feo pero accesible recuadro con scrolls para ver el contenido de la lista desordenada.

Espero sus comentarios.

Pues ayer me aventé un mensaje en twitter preguntando sobre que les gustaría que hablara en mi Blog relacionado con Javascript. El único que respondió fue el usuario Calizman y me sugería que explicara como hacer el alerta que usa twitter cuando actualizas los “settings” en tu cuenta. El efecto cociste en un mensaje que sale de la parte superior de la ventana del navegador, se despliega por unos segundos y luego se vuelve a ocultar. Hoy me puse a desarrollar el efectillo y aquí está el resultado:

<!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="en" lang="en">
<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 <title>mensaje estilo twitter</title>
 <script type="text/javascript">
 var mensaje = {
 init: function(mensaje){
 var elem = document.createElement('h1');
 elem.appendChild(document.createTextNode(mensaje));
 document.getElementsByTagName('body')[0].appendChild(elem);
 elem.setAttribute('style', 'position: absolute; margin: 0; background-color: #99F; width: 100%;top: -40px; text-align: center;');
 elem.setAttribute('id', 'msj');
 },
 activar: function(){
 intervalo = setInterval(function(){
 m = document.getElementById('msj');
 viejoTop = parseInt(m.style.top);
 if(viejoTop <= 0){
 nuevoTop = viejoTop+2;
 m.style.top = nuevoTop + 'px';
 }else{
 m.style.top = '0px';
 clearInterval(intervalo);
 setTimeout(function(){
 intervalo = setInterval(function(){
 m = document.getElementById('msj');
 viejoTop = parseInt(m.style.top);
 if(viejoTop >= -50){
 nuevoTop = viejoTop-2;
 m.style.top = nuevoTop + 'px';
 }else{
 m.style.top = '-50px';
 clearInterval(intervalo);
 }
 },10);
 }, 3000);
 }
 }, 10);
 },
 cambiarMensaje: function(mensaje){
 document.getElementById('msj').innerHTML = mensaje;
 }
 }

 window.onload = function(){
 mensaje.init('HolaMundo');
 }
 </script>
</head>
<body style="margin: 0;">
 <a href="#no" onclick="mensaje.activar();">Hola Mundo</a>
 <a href="#no" onclick="mensaje.cambiarMensaje('Mundo Hola'); mensaje.activar();">Mundo Hola</a>
</body>
</html>

Como pueden ver, he creado un miniobjeto que es el que hace todo el chistesito. Este miniobjeto cuenta con tres funciones:

init() que crea el elemento. init() recibe un único parámetro que es el texto con el que se inicializará el mensaje. En este caso  ‘Hola Mundo’. Yo estoy llamando init() al cargar la ventana, pero puede llamarse en cualquier momento, siempre y cuando 1) el documento esté totalmente cargado y 2) la llamada se haga antes de hacer cualquier llamada a uno de los otros dos métodos del objeto.

activar() es la función que se encarga de hace la animación. El código es realmentes sencillo utilizando animaciones de la vieja escuela. Pueden lograrse animaciones más sofisticadas utilizando métodos distintos, pero teniendo en cuenta que Calizman es relativamente nuevo en el mundo de Javascript, he decidido dejarlo lo más simple posible.

Por último, cambiarMensaje() se utiliza para asignar un mensage diferente al objeto y de esta forma poder usarlo para enviar distintos mensajes al usuario.

Este objeto no ha sido creado para motivos de distribución por lo que se tiene poco cuidado al momento de optimizar su comportamiento y su compativilidad. Sin embargo, unos cuantos toques por aquí y por alla y tienes un objeto totalmente transportable, aun que no realmente reusable en toda su extención.

Si tienen sugerencias sobre algo que les gustaría que explicara en un futuro, no duden enviarme un twitt a @ImBuzu o dejar la sugerencia a modo de cometario aquí en el blog.