Contenido

Modularizar aplicaciones escalables javascript con POA

13 feb

+ 11

Hace ya tiempo vimos como construir una aplicación javascript fácilmente escalable basado en una presentación de Nicholas C.Zackas. Una forma de modularizar nuestro código Javascript con la intención de separar competencias haciendo que nuestro código no sea dependiente de otro.

En el código que vimos, además encapsulábamos todos los métodos de los módulos en un gestor de errores básico que se encargaba de evitar que un error en uno de los módulos provocara que la aplicación dejara de funcionar.

...
 for (name in instance){
    method = instance[name];
    if (typeof method == "function") {
      instance[name] = function(name, method) {
      return function(){
          try { return method.apply(this, arguments);}
          catch(ex) { console.log("[Error]" + name + "(): " + ex.message); }
        }
      }(name, method);
    }
  }
...

Programación orientada a aspecto

Por otro lado, hace todavía más tiempo, vimos una implementación de los filtros de WordPress en Javascript. Una forma de acercar la programación orientada a aspectos al lado del cliente.

La programación orientada a aspectos, no es más que un paradigma de programación que nos ayuda modularizar nuestra aplicación de una forma controlada, permitiendo extenderla desde fuera sin alterar el funcionamiento principal de la misma. O lo que es lo mismo, poder desarrollar plugins que modifiquen el funcionamiento principal.

Uniendo conceptos

Uniendo conceptos podríamos disponer de la capacidad de crear aplicaciones escalables gestionadas por un objeto encargado de arrancar y/o parar módulos, con una batería de herramientas disponibles en estos módulos capaces de hacernos disfrutar de las ventajas de la programación orientada a aspectos.

Veamos el código completo:


var debug = false;
var Sandbox = function() {
	var listeners = {};
	return {
		add: function(name, func){
		  if (typeof listeners == 'undefined') return;
		  if (typeof listeners[name] == 'undefined') listeners[name] = new Array();
			listeners[name].push(func);
		},
		remove: function(name, func){
			if (typeof listeners[name] == 'undefined') return;
			var j = 0;
			while (j < listeners[name].length) {
				if (listeners[name][j] == func) { listeners[name].splice(j, 1);}
				else { j++; }
				}
		},
		fire: function(name, args){
			if (typeof listeners == 'undefined' || (!listeners[name]  || typeof listeners[name] == 'undefined')) return;
		    for (var x=0; x<listeners[name].length; x++)
		        listeners[name][x].call(this, args);
		}
	};
};

var Core = function(){
   	var modules = {}, sandbox = new Sandbox(this);
   	function createInstance(moduleID){
   		var instance = modules[moduleID].creator(sandbox),name, method;
    	if (!debug) {
      		for (name in instance){
        		method = instance[name];
        		if (typeof method == "function") {
          			instance[name] = function(name, method) {
						var evname = moduleID + ":" + name;
            			return function(){
              				try {
								sandbox.fire("pre-" + evname, arguments);
								salida = method.apply(this, arguments);
								sandbox.fire("post-" + evname, salida);
								return salida;
							}
              				catch(ex) {
								if (typeof instance["onerror"] == 'function') instance["onerror"].apply(this, [ex]);
								console.log("[Error]" + name + "(): " + ex.message);
							}
            			}
          			}(name, method);
        		}
      		}
    	}
  	return instance;
 	}

 	// Método públicos
 	return {
   		register: function(moduleID, creator) {
     		modules[moduleID] = {
       			creator: creator,
       			instance: null
     		};
   		},
   		start: function(moduleID) {
     		modules[moduleID].instance = createInstance(moduleID);
     		modules[moduleID].instance.init();
   		},
   		stop: function(moduleID){
     		var data = modules[moduleID];
     		if (data.instance) {
       			data.instance.destroy();
       			data.instance = null;
     		}
   		},
   		startAll: function(){
     		for (var moduleID in modules) {
       			if (modules.hasOwnProperty(moduleID)) {
         			this.start(moduleID);
       			}
     		}
   		},
   		stopAll: function() {
     		for (var moduleID in modules) {
       			if (modules.hasOwnProperty(moduleID)) {
         			this.stop(moduleID);
       			}
     		}
   		}
 	};
}();

¿Que nos ofrece?

He modificado el script para añadir 2 puntos de enlace predeterminados a todos los métodos de los módulos, “pre-XXX” y “post-XXX”. Lo que nos permite definir funcionalidades que se ejecutarán antes y después de la ejecución del módulo.  Veamos un ejemplo:

Core.register("test", function($s){
	return {
		init: function(){
			console.log("Constructor");
		},
		destroy: function(){
			console.log("Destroy");
		},
		onerror: function(ex){
			alert("Error: " + ex);
		}
	}
});

Core.register("test2", function($s){
	return {
		init: function(){
                        // Añadimos el evento al contructor del módulo "test"
			$s.add("pre-test:init", function(){
				console.log("Bla bla");
			});
			console.log("Constructor 2");
		},
		destroy: function(){
			console.log("Destroy 2");
		},
		onerror: function(ex){
			alert("Error: " + ex);
		}
	}
});

// Cargamos los módulos
Core.start("test2");
Core.start("test");

// Resultado
// --> Constructor 2

// --> Bla bla
// --> Constructo

Eventos personalizados

Al igual que los eventos por defecto de los que disponemos, podemos especificar eventos propios en nuestro módulos mediante el uso de Sandbox.fire(), que se encargará de ejecutar el contenido asociado al evento especificado.


Core.register("test3", function($s){
	return {
		init: function(){
			console.log("Constructor 2");
			// Ejecutamos el evento "mievento"
			$s.fire("mievento", this);
		},
		destroy: function(){
			console.log("Destroy 2");
		},
		onerror: function(ex){
			alert("Error: " + ex);
		}
	}
});

Como podemos ver, nos permitirá crear aplicaciones escalables y fácilmente extensibles mediante módulos que a su vez serán interoperables entre ellos mediante la programación orientada a aspectos.

jQuery Blog informa que deshabilitará el hotlinking

31 dic

+ 5

Desde el blog oficial de jQuery informan que apartir del próximo día 31 de enero de 2011 dejarán de servir ficheros hacia servidores externos, osea que van a deshabilitar el hotlinking que hasta ahora se estaba haciendo.

Esto afectará a muchos sitios que estén usando la dirección directa a los servidores de jQuery.com para llamar a los ficheros Javascript desde nuestras webs.

<script type="text/javascript" src="http://www.jquery.com/...."></script>

Para evitar problemas te recomiendo que cambies la ubicación de tus ficheros Javascript que hasta ahora estaban alojados en jQuery.com. Lo ideal sería alojar el fichero en tu servidor, pero si por algún motivo no es posible tienes el CDN de Google Ajax Libraries que cumple perfectamente esta función.

Validación de formularios con HTML5

18 nov

+ 14

HTML5 no solo ofrecerá una serie de elementos para hacer la web más visual, también ayudará a los desarrolladores web a realizar tareas cotidianas de forma más rápida y segura. Una de ellas es la validación de formularios.

Atributos

Gracias a una serie de atributos que podremos usar en elementos de nuestros formularios podremos condicionar desde el diseño las validaciones de cualquier formulario de nuestra página.

required

Como su nombre indica, el formulario no se enviará mientras el elemento que contenga este atributo no esté informado. Algo que hasta ahora estábamos haciendo en nuestra capa de funcionalidad con javascript, recorriendo elementos o comprobando los elementos con una class específica.

<input name="nombre" required >;

pattern

También podremos difinir el patrón que el texto deba tener dentro de nuestros elementos <input />. Este atributo realiza dos funciones, una especificar el formato del dato que recibiremos y otra la de ayudar a comprender al usuario el formato que deba usar (por ejemplo, campo para insertar un teléfono (+34) 971 123456).

<input type="telefono" pattern="(+[0-9]{2}) [0-9]{3} [0-9]{6}" >

maxlength

Podremos especificar la longitud máxima de nuestros datos directamente desde un atributo sin necesidad de controlarla desde javascript.

<textarea name="tweet" maxlength="150"></textarea>

min, max, step

Los actuales sliders pasarán a mejor vida cuando nuestros elementos se puedan definir desde nuestros elementos indicando los valores mínimos, máximos y los pasos entre ellos directamente.

<input name="slider" min="1" max="10" step="2" >

Javascript

Esto no significa que desde Javacript no vayamos a hacer nada ya con nuestros formularios, todo lo contrario, se añaden métodos nuevos a los elementos que nos permitirán trabajar con estas validaciones de una forma más cómoda.

Aún es una propuesta, pero apunta a ser una herramienta muy útil.

element.validity

Objeto que nos muestra información referente a la validación del elemento.

  • boolean valueMissing; — Devuelve true si el elemento está vacío y requerido.
  • boolean typeMismatch; — Devuelve true si el elemento no contiene la sintaxis correcta.
  • boolean patternMismatch; — Devuelve true si el elemento no cumple el patrón definido.
  • boolean tooLong; — Devuelve true si el elemento es más grande que el tamaño definido.
  • boolean rangeUnderflow; — Devuelve true si el elemento es menor al mínimo definido.
  • boolean rangeOverflow; — Devuelve true si el elemento es mayor al máximo definido.
  • boolean stepMismatch; — Devuelve true si el elemento no concuerda con uno de los pasos definidos.
  • boolean customError; — Devuelve true si el elemento tiene un error personalizado.
  • boolean valid; — Devuelve true si el elemento es válido.

element.setCustomValidity()

Método definido para especificar un mensaje de error personalizado a un elemento:

<label>Feeling: <input name=f type="text" oninput="check(this)"></label>
<script>
 function check(input) {
   if (input.value == "good" ||
       input.value == "fine" ||
       input.value == "tired") {
     input.setCustomValidity('"' + input.value + '" is not a feeling.');
   } else {
     // input is fine -- reset the error message
     input.setCustomValidity('');
   }
 }
</script>

CSS

La capa de diseño además nos permitirá informar al usuario que un elemento no ha sido validado a la hora de enviar nuestro formulario, para ello nos acercan el pseudoselector :invalid para que podamos definir el aspecto de nuestros elementos no válidos.

:invalid{
border: 1px red solid;
}

Hay muchas más y más interesantes nuevas funcionalidades que nos harán la vida más fácil, las iremos viendo más adelante.

Popcorn, dándole semántica a los videos con HTML5

8 nov

+ 3

Mozilla quiere romper la idea actual del video en Internet. El actual modelo, basado en un elemento pasivo que muestra información al usuario mediante el navegador simula perfectamente la televisión actual, pero gracias a Drumbeat ha surgido Popcorn.

Popcorn

Popcorn, es una iniciativa que añade una funcionalidad extra a los elementos <video /> y <audio /> del HTML5 permitiendo que muestren al usuario información extra sobre el video, subtítulos, geolocalización, información sobre personas que aparezcan,…

La idea es añadir una semántica extra a lo que hasta ahora solo era un canal de visualización.

XML

Mediante un fichero XML externo que definiríamos en nuestro elemento multimedia especificaremos toda la información que consideremos relevante de nuestro video.

<video width="530px" height="299px" controls="" data-timeline-sources="xml/webMadeMovies.xml">
 <source type="video/ogg; codecs="theora, vorbis" src="wmmjuly6.ogv"></source>
 <source type="video/mp4; codecs="avc1.42E01E, mp4a.40.2" src="wmmjuly6.mp4"></source>
</video>

Aquí vemos un ejemplo (recortado) del fichero XML que podríamos encontrar.

<popcorn>
 <manifest>
 <people>
 <person id="celine" name="Celine" salutation="Miss." >
 <resource id="celinehomepage" src="http://www.celinecelines.com/" description="Celine's Homepage" />
 </person>
 <person id="brian" name="brian" >
 </person>
 <person id="SteveSong" name="Steve Song" >
 </person>
 [...]
 </people>
 <places>
 <place id="saopaulo" type="city" name="Sao Paulo">
 <resource id="saopaulowiki" src="http://en.wikipedia.org/wiki/S%C3%A3o_Paulo" description="Sao Paulo city, Brazil"/>
 </place>
 <place id="CapeTown" type="city" name="Cape Town">
 <resource id="capetownwiki" src="http://en.wikipedia.org/wiki/Cape_Town" description="Cape Town, South Africa"/>
 </place>
 [...]
 </places>
 <attributions>
 <attribution id="yacht1attrib" nameofwork="Don't Fight The Darkness" copyrightholder="Yacht" copyrightholderurl="http://www.teamyacht.com/" nameofworkurl="http://freemusicarchive.org/curator/WFMU/blog/Join_YACHT_See_Mystery_Lights_instrumentals" license="CC-BY-NC" licenseurl="http://creativecommons.org/licenses/by-nc/2.0/"/>
 <attribution id="yacht2attrib" nameofwork="Psychic City Voodoo City" copyrightholder="Yacht" copyrightholderurl="http://www.teamyacht.com/" nameofworkurl="http://freemusicarchive.org/curator/WFMU/blog/Join_YACHT_See_Mystery_Lights_instrumentals" license="CC-BY-NC" licenseurl="http://creativecommons.org/licenses/by-nc/2.0/"/>
 <attribution id="attrib" nameofwork="A Shared Culture" copyrightholder="Jesse Dylan" license="CC-BY-NC" licenseurl="http://creativecommons.org/licenses/by-nc/2.0/"/>
 [...]
 </attributions>
 <articles>
 <resource id="theinternet" src="http://en.wikipedia.org/wiki/internet" description="The Internet"/>
 <resource id="villagetelco" src="http://en.wikipedia.org/wiki/Village_telco" description="The Village Telco"/>
 <resource id="oilspill" src="http://en.wikipedia.org/wiki/Deepwater_Horizon_oil_spill" description="Deepwater Horizon Oil Spill"/>
 [...]
 </articles>
 </manifest>

 <timeline>
 <footnotes>
 <footnote in="00:00:00" out="00:14:00" target="footnotediv">Look around the page as info is updated!</footnote>
 </footnotes>
 <resources>
 <attribution in="00:00:05:02" out="00:00:34:00" target="container5" resourceid="yacht1attrib"></attribution>
 <attribution in="00:00:34:01" target="container5" resourceid="yacht1attrib"></attribution>
 <footnote in="00:00:00" out="00:15:00" target="footnotediv">Look around the page!</footnote>
 <videotag in="00:00:05:02" out="00:00:10:07">Steve Song</videotag>
 <attribution in="00:00:05:02" out="00:00:10:07" target="container5" resourceid="villagetelcoattrib"></attribution>
 <twitter in="00:00:05:02" out="00:00:10:07" title="Steve Song" source="from:stevesong" target="personaltwitter" width="238" height="120" overlay="images/overlay/twitter.png" />
 <wiki in="00:00:05:02" out="00:00:10:07" resourceid="villagetelco" numberOfWords="200" target="wikidiv" overlay="images/overlay/wiki.png"/>
 <flickr in="00:00:05:02" out="00:00:10:07" target="personalflickr" userid="78868639@N00" numberofimages="8" padding="4px" overlay="images/overlay/flickr.png"/>
 <googlenews in="00:00:05:02" out="00:00:10:07" target="googlenewsdiv" topic="Village Telco"/>
 [...]
 </resources>

 <map>
 <location resourceid="capetownwiki" in="00:00:03:00" out="00:00:11:07" lat="-33.9238" long="18.4233" target="container2" zoom="8"/>
 <location resourceid="grandislewiki" in="00:00:11:07" out="00:00:19:07" lat="29.2720" long="-90.0233 " target="container2" zoom="8"/>
 <location resourceid="mitmedialabhome" in="00:00:19:08" out="00:00:27:00" lat="42.3613" long="-71.0863" target="container2" zoom="12"/>
 [...]
 </map>
 <subtitles>

 <subtitles language="en" align="center">
 <subtitle in="00:00:00:03" out="00:00:01:06">All right let's take a look and show me some</subtitle>
 <subtitle in="00:00:01:06" out="00:00:03:00">of the neat things you can do on the internet</subtitle>
 [...]
 </subtitles>

 <subtitles language="fa" align="center">

 <subtitle in="00:04:00:08" out="00:04:01:09">My name is Mona Kasra</subtitle>

 <subtitle in="00:04:01:10" out="00:04:03:11">and I'm building a better Internet</subtitle>
 [...]
 </subtitles>

 </subtitles>
 <credits></credits>
 </timeline>
</popcorn>

Uno de los ejemplos de uso de este tipo de información es la de enviar en tiempo real los subtítulos en Inglés a una herramienta de traducción para mostrarlos en un idioma diferente al definido en el XML.

Sin duda se trata de un interesante proyecto que Mozilla está apoyando con el que los videos/audios de Internet dejarán de ser lo que son hoy en día.

IE9 el más estándar con HTML5

2 nov

+ 13

Lo he visto en Alt1040 y no me lo creía, así que he indagado un poco y no he podido encontrar pruebas de que esta noticia sea falsa, es más, al parecer la W3C se ha encargado de avalar la preview 6 de Internet Explorer 9 como la más estándar con respecto a HTML5 de todos los navegadores actuales.

HTML5browsers
(Ver Imagen)

Ya lo dije en su momento, esta nueva versión me está dando muy buenas vibraciones, eso no significa que deje de mirar de estar espectante para ver por donde va la cosa.

MIME Type Javascript soportados

2 nov

+ 1

¿Alguna vez te has preguntado que tipos de Javascript podemos definir al cargar nuestros scripts? Y quizás, lo más importante. ¿En que navegadores funcionarán?

<script type="text/javascript" src=""></script>

Krijn Hoetmer lo hizo y nos dejó estos resultados:

javascript-mime-types
(Ver Imagen)

Un dato que aunque no es realmente importante, nunca deja de ser curioso :D

Listado de propiedades CSS compatibles con todos los navegadores

2 nov

+ 5

Las propiedades CSS son los frágiles pilares sobre los que se sustentan todos los diseños web. Estos pilares son delgados y generalmente andamos poniendo parches para que el diseño soporte la llegada del inquilino de turno, ya sea el Sr. Firefox o la Srta. Google Chrome, o incluso el veterano Internet Explorer.

Debido a la exigencia de cada uno de los inquilinos, nos vemos obligados a aprender todos los trucos disponibles para hacer que su estancia en nuestra construcción sea lo más cómoda y agradable posible.

A estas alturas, sabemos que estas 10 propiedades CSS son completamente compatibles con todos ellos:

  1. color
  2. direction
  3. font-family
  4. font-size
  5. font-style
  6. font-weight
  7. list-style-position
  8. table-layout
  9. text-indent
  10. word-wrap

Por contra, todas estas hacen sacar lo mejor de nosotros para conseguir que soporten el peso de cada visita:

  1. background
  2. background-attachment
  3. background-color
  4. background-image
  5. background-repeat
  6. background-position
  7. border
  8. border-collapse
  9. border-color
  10. border-style
  11. border-width
  12. clear
  13. cursor
  14. display
  15. float
  16. font
  17. font-variant
  18. height
  19. left
  20. right
  21. bottom
  22. top
  23. letter-spacing
  24. line-height
  25. list-style
  26. list-style-image
  27. list-style-type
  28. margin
  29. overflow
  30. padding
  31. page-break-after
  32. page-break-before
  33. position
  34. text-align
  35. text-decoration
  36. text-transform
  37. vertical-align
  38. visibility
  39. white-space
  40. width
  41. word-spacing
  42. z-index

Esperemos que poco a poco vayamos viendo menguar esta lista para hacernos la vida más fácil.

Protocolo relativo de URLs

28 oct

+ 14

Paul Irish publica un interesante truco para facilitarnos el trabajo con las URL’s de nuestras aplicaciones web.

<img src="//domain.com/img/logo.png">

De esta forma, el navegador selecciona por nosotros el protocolo que debe usar, que en todo caso será el mismo en el que estemos corriendo la aplicación. Ideal para los casos en los que disponemos de secciones en HTTPS y otras en HTTP, para evitar el molesto mensaje de error.

Al igual que si estamos usando el protocolo file:// desde nuestra máquina, tambien usará esa ruta de ficheros dentro de nuestro disco duro para intentar cargar la la URL indicada.

En los ficheros CSS tambien podemos usar esta técnica, aunque en Internet Explorer 7 y 8 provoca un fallo que hace que el fichero se descargue dos veces (¬¬).

.omgomg { background: url(//websbestgifs.net/kittyonadolphin.gif); }

Técnicamente se llama “Relative Reference” y está especificada en el RFC 3986.

ART, librería gráfica de la gente de MooTools

13 oct

+ 1

Ayer vimos que MooTools se actualizaba hasta la versión 1.3. David Walsh habla sobre ella y además nos deja los dientes largos con ART. Un proyecto independiente, al igual que Slick, que podrá agregarse fácilmente a MooTools, y que está pensado para facilitar la tarea de trabajar con gráficos vectoriales desde Javascript.

El uso de <canvas /> y VML permitirá crear elementos gráficos como estos:

Captura de pantalla 2010-10-12 a las 23.57.08
(Ver Imagen)

Habrá que estar pendiente, esto tiene muy buena pinta.

Ver algunos ejemplos

Selectivizr, añade pseudo-clases y atributos CSS3 a IE6-8

6 sep

+ 8

:Select[ivizr] es una librería javascript que nos permite llevar las pseudo-clases y atributos de CSS3 a navegador que no los soportan como Internet Explorer.

Instalación

Pensado para funcionar con las principales librerías Javascript existentes, su uso es muy sencillo.


<script type="text/javascript" src="[JS library]"></script>
<!--[if (gte IE 6)&(lte IE 8)]>
  <script type="text/javascript" src="selectivizr.js"></script>
  <noscript><link rel="stylesheet" href="[fallback css]" /></noscript>
<![endif]-->

Una alternativa interesante para los que no estén satisfechos con ie-css3.js.