Contenido

Scripts que se auto programan en javascript

21 ene

+ 16

Hace tiempo que javascript me tiene enamorado y poco a poco voy descubriendo nuevas propiedades y nuevas técnicas de programación que no podríamos tener en otros lenguajes.

Una curiosidad de javascript es la de poder igualar variables a funciones:

function nombre(){ alert("Hola"); }

//
 var variable = nombre();
// -> Muestra un alert()

 console.log(variable.toString());
// TypeError: variable is undefined

// igualamos
var foo = nombre;

console.log(foo.toString());
//function nombre() { alert("Hola"); }

Como vemos en el ejemplo anterior, si deseamos igualar una variable a una función deberemos hacer sin añadir los paréntesis que se añaden habitualmente a las funciones, añadir los paréntesis implica la ejecución de la función. De esta forma, podemos aprovecharnos de dicha propiedad para hacer cosas interesantes:

var $$$ = function(){
	if (document.getElementsByClassName){
		return function(klass){
			return document.getElementsByClassName(klass);
		}
	} else {
		return function(klass){
			var result = new Array();
			var reg = new RegExp( "(?:^|\\s)" + klass.replace( /\./g, "\\s*" ) + "(?:\\s|$)" );
			var es = (document.all) ? document.all : document.getElementsByTagName("*");
			for( var index = 0, e; e = es[ index++ ]; ) {
				if( reg.test( e.className ) ) {
					result[ result.length ] = e;
				}
			}
			return result;
		}
	}
}()

Este ejemplo nos sirve para ilustrar lo que intento explicar en este artículo. Si nos fijamos en el código, está condicionado por la existencia del método getElementsByClassName del objeto document, en caso de existir devolvemos una función que la usa para obtener los elementos con la clase solicitada.

En caso de no existir dicho método, se encarga de devolver una funcionalidad desarrollada usando getElementsByTagName con la que obtenemos el mismo resultado pero en navegadores donde getElementsByClassName no está disponible.

Al final del código (y en negrita) vemos los famosos paréntesis de los que hemos hablado antes. En este caso, ejecutará dicho código una vez pase por él, dejándonos la variable $$$ cargada con el método que más le convenga dependiendo de la existencia del método getElementsByClassName.

Hagamos unas pruebas :D

var $$$ = function(){
	if (document.getElementsByClassName){
		return function(klass){
			return document.getElementsByClassName(klass);
		}
	} else {
		return function(klass){
			var result = new Array();
			var reg = new RegExp( "(?:^|\\s)" + klass.replace( /\./g, "\\s*" ) + "(?:\\s|$)" );
			var es = (document.all) ? document.all : document.getElementsByTagName("*");
			for( var index = 0, e; e = es[ index++ ]; ) {
				if( reg.test( e.className ) ) {
					result[ result.length ] = e;
				}
			}
			return result;
		}
	}
}()

// Con getElementsByClassName
$$$.toString()
// --> "function (klass) { return document.getElementsByClassName(klass); }"

$$$("framework")
// --> [th.framework, th.framework, th.framework, th.framework, th.framework, th.framework]

//Sin getElementsByClassName
$$$.toString()
// --> "function (klass) { var result = new Array; var reg = new RegExp("(?:^|\\s)" + klass.replace(/\./g, "\\s*") + "(?:\\s|$)"); var es = document.all ? document.all : document.getElementsByTagName("*"); for (var index = 0, e; e = es[index++];) { if (reg.test(e.className)) { result[result.length] = e; } } return result; }"

$$$("framework")
// --> [th.framework, th.framework, th.framework, th.framework, th.framework, th.framework]

Ventajas

Al ser ejecutado al cargar el script tenemos una ventaja a la hora de ejecutar dicho método, no tendremos que realizar una comprobación de la función para elegir un camino u otro, la función ya estará cargada con el camino correcto que debe usar, en el caso del elemento el getElementsByClassName.

Desventajas

Perdemos unas milésimas de segundo en la carga del fichero, esto es debido a que ha de compilar el código y ejecutar la función, en este caso el tiempo no es significativo, pero en scripts más pesados y/o complejos puede llegar a notarse dicho tiempo, dependiendo el uso de la funcionalidad nos puede ser interesante usarlo o no.

¿Alguien sabe que nombre recibe esta técnica? Llevo tiempo usándola, pero nunca he sabido el nombre que recibe.

Actualización

Me he olvidado de algo que podría ser interesante. Resulta que además de esta funcionalidad, disponemos de la posibilidad de pasar una variable a la función y usarla dentro de la función que estamos auto generando.

var foo = true; // o false;

var func = function(bla){
	if (bla){
		return function(str){
			console.log("USAMOS CONSOLE: " + str);
		}
	} else {
		return function(str){
			alert("USAMOS ALERT: " +str);
		}
	}
}(foo)

En el ejemplo nos encontramos la declaración de la función que recibe un parámetro llamado bla, parámetro que pasamos en la última línea, entre los parámetros usando la variable foo. Dentro podremos usar bla que es el parámetro que estamos recibiendo dentro. Una curiosa forma de auto programar nuestras aplicaciones :D

Recopilación de cosillas interesantes

21 ene

+ 6

Me he pasado unos días peleandome con código y no he tenido tiempo de escribir, pero creo que hay cosas que valen la pena conocer para estar más al día en el mundillo en el que nos movemos.

Date Range Picker, llevando los selectores del fecha más allá

17 ene

+ 7

Date Range Picker se ha actualizado para utilizar la nueva versión de jQuery UI, la 1.6. Con ello han conseguido darle una apariencia interesante y sobretodo fluida a este selector de fechas basado en jQuery.Tan solo 13kb de código que funciona en los principales navegadores web y nos permite personalizar hasta el más pequeño detalle.[Demo][Descargar]

$fx(), un framework para animaciones

17 ene

+ 5

En Sentido Web nos hablan hoy sobre $fx(), un framework javascript especializado en gestionar animaciones. Y es que $fx() es un framework de tan solo 3,7kb que nos permite aplicar animaciones a nuestras aplicaciones web de una manera sencilla y potente.

Dispone de unos pocos, muy pocos métodos, pero suficientes para dotar de vida animada a nuestras aplicaciones.

  • $fx() — inicialización
  • fxAdd() — añadimos un nuevo efecto (opacity, backgroundx, backgroundy)
  • fxAddSet() — añadimos un set de efectos
  • fxHold() — añadimos una pausa antes de ejecutar
  • fxPause() — pausamos la animación
  • fxStop() — paramos la animación
  • fxReset() — borramos todas las animaciones.
  • fxRun() — arrancamos las animaciones.

Ejemplo de uso

var moveBg0 = {type: 'backgroundx', to: -314, step: -1, delay: 20}
var moveBg1 = {type: 'backgroundx', to: -269, step: -1, delay: 50}
var stars = document.getElementById('sample1').getElementsByTagName('div');

$fx(stars[0]).fxAdd(moveBg0).fxRun(null, -1);
$fx(stars[1]).fxAdd(moveBg1).fxRun(null, -1);

Ejemplos

Os recomiendo que le echeis un vistazo a los ejemplos que nos han puesto para abrir boca.

Descargar

Versión 0.1

XUI, un framework para dispositivos móviles

17 ene

+ 1

XUI es un framework muy liviano adaptado únicamente a los dispositivos móviles, al contrario que los que ya conocemos, como jQuery, MooTools, Prototype, Dojo,… que están pensados para funcionar en todos los navegadores posibles, XUI se encarga de ofrecer únicamente las funcionalidades que un dispositivo móvil puede necesitar, todo ello en tan solo 6Kb.

Inicialmente está pensado para trabajar con móviles con navegadores basados en WebKit, Fennec y Opera y tienen previsto sacar una versión compatible con Internet Explorer Mobile y Blackberry. Por el momento está bastante verde, pero parece prometedor.

DOM

  • html()
x$(window).html( location, htmlFragment );

Events

  • click()
  • load()
  • touchstart()
  • touchmove()
  • touchend()
  • touchcancel()
  • gesturestart()
  • gesturechange()
  • gestureend()
  • orientationchange()
x$(window).load(function(e){
	x$('.save').touchstart( function(evt){ alert('tee hee!') });
});

Styles

  • setStyles()
  • getStyles()
  • addClass()
  • removeClass()
  • css()
x$('DIV').setStyle('width','100px');
x$('#box5').css({ backgroundColor:'blue', width:'100px', border:'2px solid red' });

Fx

  • tween()
x$('#box').tween([{ left:100px, backgroundColor:'green', duration:.2 }, { right:100px }]);

XHR

  • xhr()
  • xhrjson()
xhr('path/to/file.html', {});

¡En Safari de Windows todos los frameworks vuelan!

15 ene

+ 28

Mirar que curioso lo que me ha ocurrido al probar el test de selectores con Safari para Windows.

test_selectors

Devuelve el número correcto de elementos y en pruebas posteriores he visto frameworks fallando, pero esta imagen es la tercera que saco consecutiva…  Interesante ¿verdad?

Selectores CSS y frameworks actuales

14 ene

+ 18

Estoy haciendo, a modo de trabajo de investigación un selector CSS muy básico para entender como funcionan los desarrollados por los principales frameworks. Aún está muy lejos de llamarse selector ya que únicamente permite hacer búsquedas muy ligeras y no he testado mucho los posibles problemas.

var js2k = {
	cache: {},
	cleanCache: function(){
		this.cache = {};
	},
	trim: function(string){
		return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	},
	get: function(selector, context, cache) {
		var cache = cache || false;
		// Navegadore modernos
		if (document.querySelectorAll) return document.querySelectorAll(selector);

		// Navegadores MUY antiguos
		if (!document.getElementsByTagName) { return new Array();}
		if (cache && this.cache[selector]) return this.cache[selector];

		var tokens = selector.split(' ');
		var context = new Array(context || document);
		for (var i = 0; i < tokens.length; i++) {
			var found = new Array, h = 0;
			token = this.trim(tokens[i]);

			// ID
			if (token.indexOf('#') > -1) {
				var el = this.getID(token);
				context = el?new Array(el):new Array;
				continue;
			}    

			// Class
			if (token.indexOf('.') > -1) {
				while(h<context.length)
						found = found.concat(this.getClass(token, context[h++]));
				context = found;
				continue;
			}

			// Tag
			while(h<context.length)
				found = found.concat(this.toArray(this.getTag(token, context[h++])));
			context = found;
		}
		if (cache) this.cache[selector] = context;
		return context;
	},
	getID: function(token){
		var bits = token.split('#');
		return document.getElementById(bits[1]);
	},
	getClass: function(token, context) {
		var context = context || document;
		var bits = token.split('.');
		var tagName = bits[0]?bits[0]:"*",className = bits[1], result = new Array;
		if (context.getElementsByClassName) {
			var found = this.toArray(context.getElementsByClassName(className));
			if (tagName == "*") return found;
			var regExp = new RegExp(tagName, "i");
			for (var x in found)
				if (regExp.test(found[x].tagName)) result.push(found[x]);
		} else {
			var t = context.getElementsByTagName(tagName);
	    	var oRegExp = new RegExp("(^|\\s)" + className.replace(/\-/g, "\\-") + "(\\s|$)");
			for (var y in t)
				if (oRegExp.test(t[y].className)) result.push(t[y]);
		}
		return result;
	},
	getTag: function(token, context){
 	    return (context || document).getElementsByTagName(token);
	},
	toArray: function(els){
			return Array.prototype.slice.call(els);
	}
}

Bueno, hasta aquí todo normal, pero cuando he querido hacer pruebas de velocidad para comparar los tiempos con los selectores más rápidos actuales me he encontrado con una curiosidad.

diff_selectors

Si nos fijamos en la imagen superior y buscamos la línea de resultados para la búsqueda de elementos “div p” vemos que todos los frameworks devuelven 140 elementos excepto js2k (si, soy super original xD) que devuelve 142, es un problema de mi script.

El problema lo he podido reproducir en Firefox 3.05, Opera 9,63 (sobre Leopard)  y en Firefox 3.1 , Safari/WebKit el resultado de todos los frameworks, es 140, incluso js2k.

¿Por que?

Pues despues de rebanarme los sesos media tarde he dado con el problema. Al parecer, las estructuras estas no le gustan a mi script:

<div>
	<div>
		<p>Bla</p>
	</div>
</div>
<div>
	<p>Bla</p>
</div>;

Si lanzo una búsqueda sobre esta estructura en Firefox 3.0.5 o Opera 9.63, obtengo 3 elementos <p /> en lugar de 2. Esto se debe a que guardo los elementos <div />; para buscar en cada uno de ellos los siguientes elementos, en este caso los <p />. El fallo está en que mi script almacena 3 <div /> diferentes cuando deberían ser solo 2.

Pero en Firefox 3.1 y Safari/WebKit obtenemos un resultado correcto, osea 2 elementos <p />

He montado un pequeño script donde podemos probarlo nosotros mismo. Solo debería devolver 3 párrafos. ¿Curioso no?

Lanzamiento de jQuery 1.3

14 ene

+ 10

Hoy, 14 de enero de 2009, jQuery 1.3 ve la luz y nos sorprende con muchas mejoras que harán de este framework una herramienta todavía más útil.

Sizzle

3196296260_c7a0be70be

Para empezar, la incorporación de Sizzle hace que la velocidad en búsqueda de selectores se vea incrementada y ofrezca unos resultados muy interesantes.

Delegación de eventos

Con la delegación de eventos el generar elementos dinámicamente no implicará tener que definir nuevamente los eventos asociados al tipo de elemento generado.

$("p").live("click", function(){
$(this).after("<p>Another paragraph!</p>");
});

jQuery.Event

Se ha creado un elemento Event para gestionar más fácilmente los eventos y así encapsularlos para obtener todas las funcionalidades especificadas por la W3C en todos los navegadores.

Inyección HTML reescrita

3196296910_6d385bd9df

Los métodos jQuery.html(), .append(),.. encargados de generar HTML dinámicamente han sido reescritos obteniendo una mejora de un 6x en algunos casos sobre jQuery 1.2.6.

Mejorado el método .offset()

La reimplementado el método offset() para mejorar su velocidad y se ha conseguido mejorar hasta 3x la velocidad con respecto a la 1.2.6.

Eliminación del Browser Sniffing

En esta versión llama mucho la atención de que no se compruebe mediante el browser/useragent el navegador del usuario lo que ha hecho que la velocidad en general del framework tambien se vea afectada. Para evitar problemas con los scripts que usar jQuery.browser, aún está cargado en el core y será eliminado el futuras revisiones.

Descargar

jQuery Minified / jQuery Regular

Usar con Google Ajax Libraries

Los que usamos Google Ajax Libraries para no tener que alojar jQuery en nuestros servidores podemos usarlo mediante esta URL:

http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js

Facebox 1.2, el lightbox de Facebook con jQuery

13 ene

+ 9

Otro Lightbox entra en escena, en esta ocasión es Facebox 1.2, una implementació del que podemos ver en Facebook para mostrarnos alertas sobre nuestros contactos. [Demo][Descargar]

El motivo por el que Internet Explorer es el mejor navegador

13 ene

+ 42

internet-explorer-can-you-do-this-with-firefox

<ironia>Es que ningún otro navegador es capaz de mostrar tantas imagenes a la vez… </ironia>

<sarcasmo>¡¡Larga vida a Internet Explorer!!</sarcasmo>