Serialización de llamadas Ajax con Prototype

Jueves, 2 Agosto 2007 2 comentarios

En javascript un caso que se puede dar, aunque no demasiado común, consiste en necesitar serializar llamadas Ajax asíncronas, es decir, realizar una serie de llamadas Ajax asíncronas de forma que el usuario puede seguir manejando la página pero que las llamadas se realicen en el orden en que se vayan pidiendo de forma que al servidor sólo le lleguen las llamadas una detrás de otra sin que se pueda dar el caso de realizar dos llamadas Ajax simultáneas al servidor.

Para ello, he creado un código que permite realizar esta tarea y cuya utilización es muy sencilla: una vez importado el código, para serializar las llamadas sólo hay que llamarlo de la siguiente forma:


AjaxSerializer.request(url1, options1);
AjaxSerializer.request(url2, options2);
AjaxSerializer.request(url3, options3);
...

En donde url y options son los mismos parámetros que pasarías en una llamada a la clase Ajax.Request de Prototype

Aquí va el snippet:


AjaxSerializer = Class.create();
AjaxSerializer.prototype = {
    _activeRequestCount: 0,
    _pendingData: new Array(),

    initialize: function() {
        Ajax.Responders.register({
            onComplete: function() {
                if (this._pendingData.length > 0) {
                    var url = this._pendingData.shift();
                    var opts = this._pendingData.shift();
                    this._activeRequestCount++;
                    new Ajax.Request(url, opts);
                }
                this._activeRequestCount--;
            }.bind(this)
        });
    },

    request: function(url, opts) {
        if (this._activeRequestCount == 0) {
            this._activeRequestCount++;
            new Ajax.Request(url, opts);
        } else {
            this._pendingData.push(url, opts);
        }
    }
}
var AjaxSerializer = new AjaxSerializer();


Teclas de acceso rápido

Miércoles, 26 Abril 2006 5 comentarios

Portapapeles

  • CTRL+A Selecciona todos los elementos de la ventana activa
  • CTRL+C Copia el elemento o elementos seleccionados al Portapapeles
  • CTRL+X Corta el elemento o elementos seleccionados al Portapapeles
  • CTRL+V Pega el elemento o elementos seleccionados del Portapapeles
  • CTRL mientras se arrastra un elemento Copia dicho elemento
  • CTRL+SHIFT con las flechas selecciona un bloque de texto

Ventanas de diálogo

  • WINDOWS+E Abre el explorador de archivos
  • WINDOWS+F Busca un archivo o carpeta
  • CTRL+WINDOWS+F Busca ordenadores de la red local
  • WINDOWS+F1 Visualiza la ayuda de Windows
  • WINDOWS+L Bloquea el teclado
  • WINDOWS+R Abre el diálogo de Ejecutar
  • WINDOWS+U Abre el administrador de utilidades

Gestión de ventanas

  • ALT+TAB Cambia entre aplicaciones abiertas
  • ALT+ESC Cambia entre aplicaciones abiertas en el orden en que fueron abiertas
  • CTRL+F4 Cierra la ventana del documento activo de la aplicación abierta
  • CTRL+F6 Abre la siguiente ventana de documento en la aplicación activa
  • ALT+F4 Cierra el programa activo en ese momento
  • ALT+ESPACIO Abre el menú rápido de la ventana activa
  • F5 Actualiza la ventana activa
  • CTRL+TAB Pasa a la pestaña siguiente
  • CTRL+SHIFT+TAB Pasa a la pestaña anterior

Explorador de archivos

  • NUM LOCK+Asterisco (*) Visualiza todas las carpetas bajo la carpeta seleccionada
  • Signo + Visualiza las subcarpetas de la capeta actual
  • Signo - Colapsa las subcarpetas de la carpeta actual

Varios

  • ALT+ENTER Ver las propiedades del elemento seleccionado
  • TAB Mover la selección al siguiente elemento
  • ENTER Ejecuta la acción del botón seleccionado
  • ESPACIO Selecciona o desselecciona un checkbox si está seleccionado

Visto en Digg hace un par de días. Aunque hay un par de combinaciones que no aparecen y son geniales:

CTRL+ALT+Flecha Arriba/Flecha Abajo Gira la pantalla 180º


DOMBuilder

Miércoles, 19 Abril 2006 No hay comentarios

Si estás cansado de usar el innerHTML o crear los elementos HTML a manita uno a uno con javascript mediante DOM prueba DOMBuilder. Te permite crear elementos de una forma muy sencilla e intuitiva. Por ejemplo, para crear un formulario con dos campos, email y contraseña, bastaría el siguiente código:

var html = DomBuilder.apply();
var form = html.FORM(
  html.DIV(
    html.INPUT({type : 'text', name : 'email'}),
    html.INPUT({type : 'text', name : 'password'}),
    html.INPUT({type : 'submit'}),
  )
);
document.body.appendChild(form);

Lo mejor es que la librería sólo ocupa 1Kb de los cuales 500 bytes son la información legal :)

Puedes ir a la página del desarrollador para ver más información o descargar el dombuilder.js directamente.


Compactador de javascript

Martes, 21 Febrero 2006 8 comentarios

Si has visto alguna vez el código fuente de GMail habrás observado que el código está compactado perfectamente para ahorrar ancho de banda y tiempo de descarga a los usuarios. En esta web hay una pequeña utilidad que se maneja en la línea de comandos y que permite hacer eso mismo, compactar cualquier javascript que tengas eliminando comentarios, retornos de carro, tabuladores, espacios innecesarios…

He cogido el código fuente y lo he traducido a javascript lo cual permite que se pueda ejecutar en un entorno más “acogedor” ;)

<html>
<body>
<script language="javascript">
<!--
var theA;
var theB;

var entrada = "";
var out = "";

function in_read() {
    if (entrada.length > 0) {
        var ret = entrada.charAt(0);
        entrada = entrada.substr(1);
        return ret;
    }
    return -1;
}

function in_unread(character) {
    entrada = character + entrada;
}

function out_write(character) {
    out = out + character;
}

function get() {
    var c = in_read();
    if (c >= " " || c == "\n" || c == -1) {
        return c;
    }
    if (c == "\r") {
        return "\n";
    }
    return " ";
}
   
function peek() {
    var lookaheadChar = in_read();
    in_unread(lookaheadChar);
    return lookaheadChar;
}

function next() {
    var c = get();
    if (c == "/") {
        switch (peek()) {
            case "/":
                for (;;) {
                    c = get();
                    if (c <= "\n") {
                        return c;
                    }
                }
            case "*":
                get();
                for (;;) {
                    switch (get()) {
                    case "*":
                        if (peek() == "/") {
                            get();
                            return " ";
                        }
                        break;
                    case -1:
                        return;
                    }
                }
            default:
                return c;
        }
    }
    return c;
}

function action(d) {
    switch (d) {
        case 1:
            out_write(theA);
        case 2:
            theA = theB;
            if (theA == "\"" || theA == """) {
                for (;;) {
                    out_write(theA);
                    theA = get();
                    if (theA == theB) {
                        break;
                    }
                    if (theA <= "\n") {
                        return;
                    }
                    if (theA == "\\") {
                        out_write(theA);
                        theA = get();
                    }
                }
            }
        case 3:
            theB = next();
            if (theB == "/" && (theA == "(" || theA == "," || theA == "=")) {
                out_write(theA);
                out_write(theB);
                for (;;) {
                    theA = get();
                    if (theA == "/") {
                        break;
                    } else if (theA == "\\") {
                        out_write(theA);
                        theA = get();
                    } else if (theA <= "\n") {
                        throw new UnterminatedRegExpLiteralException();
                    }
                    out_write(theA);
                }
                theB = next();
            }
    }
}

function jsmin() {
    entrada = document.getElementById("js_source").value;
    out = "";
    theA = "\n";
    action(3);
    while (theA != -1) {
        switch (theA) {
            case " ":
                if (isAlphanum(theB)) {
                    action(1);
                } else {
                    action(2);
                } break;
            case "\n": 
                switch (theB) {
                    case "{":
                    case "[":
                    case "(":
                    case "+":
                    case "-":
                        action(1); 
                        break;
                    case " ":
                        action(3);
                        break;
                    default:
                        if (isAlphanum(theB)) { 
                            action(1);
                        } else {
                            action(2);
                        }
                    }
                break;
            default:
                switch (theB) {
                    case " ": 
                        if (isAlphanum(theA)) {
                            action(1);
                            break;
                        }
                        action(3);
                        break;
                    case "\n": 
                        switch (theA) {
                            case "}":
                            case "]":
                            case ")":
                            case "+":
                            case "-":
                            case """: 
                            case "\"":
                                action(1);
                                break;
                            default:
                                if (isAlphanum(theA)) {
                                    action(1);
                                } else {
                                    action(3);
                                }
                             }
                             break;
                    default:
                        action(1);
                        break;
                }
        }
    }
    document.getElementById("js_target").value = out;
}

function isAlphanum(c) {
    return ((c >= "a" && c <= "z") || 
            (c >= "0" && c <= "9") || 
            (c >= "A" && c <= "Z") || 
            c == "_" || 
            c == "$" || 
            c == "\\" || 
            c > 126);
}
//-->
</script>
<textarea id="js_source" cols="60" rows="10"></textarea>
<br />
<input type="button" value="Minimiza!" onclick="jsmin();return false"/>
<br />
<textarea id="js_target" cols="60" rows="10"></textarea>
</body>
</html>

Como ejemplo, éste es el javascript ya compactado por él mismo, tiene una ganancia de casi el 50% de espacio:

<html>
<body>
<script language="javascript">
<!--
var theA;var theB;var entrada="";var out="";function in_read(){if(entrada.length>0){var ret=entrada.charAt(0);entrada=entrada.substr(1);return ret;}
return-1;}
function in_unread(character){entrada=character+entrada;}
function out_write(character){out=out+character;}
function get(){var c=in_read();if(c>=" "||c=="\n"||c==-1){return c;}
if(c=="\r"){return"\n";}
return" ";}
function peek(){var lookaheadChar=in_read();in_unread(lookaheadChar);return lookaheadChar;}
function next(){var c=get();if(c=="/"){switch(peek()){case"/":for(;;){c=get();if(c<="\n"){return c;}}
case"*":get();for(;;){switch(get()){case"*":if(peek()=="/"){get();return" ";}
break;case-1:return;}}
default:return c;}}
return c;}
function action(d){switch(d){case 1:out_write(theA);case 2:theA=theB;if(theA=="\""||theA=="""){for(;;){out_write(theA);theA=get();if(theA==theB){break;}
if(theA<="\n"){return;}
if(theA=="\\"){out_write(theA);theA=get();}}}
case 3:theB=next();if(theB=="/"&&(theA=="("||theA==","||theA=="=")){out_write(theA);out_write(theB);for(;;){theA=get();if(theA=="/"){break;}else if(theA=="\\"){out_write(theA);theA=get();}else if(theA<="\n"){throw new UnterminatedRegExpLiteralException();}
out_write(theA);}
theB=next();}}}
function jsmin(){entrada=document.getElementById("js_source").value;out="";theA="\n";action(3);while(theA!=-1){switch(theA){case" ":if(isAlphanum(theB)){action(1);}else{action(2);}break;case"\n":switch(theB){case"{":case"[":case"(":case"+":case"-":action(1);break;case" ":action(3);break;default:if(isAlphanum(theB)){action(1);}else{action(2);}}
break;default:switch(theB){case" ":if(isAlphanum(theA)){action(1);break;}
action(3);break;case"\n":switch(theA){case"}":case"]":case")":case"+":case"-":case""":case"\"":action(1);break;default:if(isAlphanum(theA)){action(1);}else{action(3);}}
break;default:action(1);break;}}}
document.getElementById("js_target").value=out;}
function isAlphanum(c){return((c>="a"&&c<="z")||(c>="0"&&c<="9")||(c>="A"&&c<="Z")||c=="_"||c=="$"||c=="\\"||c>126);}//-->
</script>
<textarea id="js_source" cols="40" rows="10"></textarea>
<br />
<input type="button" value="Minimiza!" onclick="jsmin();return false"/>
<br />
<textarea id="js_target" cols="40" rows="10"></textarea>
</body>
</html>

Si quieres hacer una prueba con tu propio código lo puedes hacer aquí:





Yahoo! Library

Miércoles, 15 Febrero 2006 1 comentario

Yahoo! ha dado un campanazo lanzando una librería javascript que permite la creación de clientes web “enriquecidos” con controles como árboles, calendarios, uso de ajax de forma simplificada, …

Todavía no he podido meterle mano pero tiene una pinta estupenda además de la documentación con la que viene. Por cierto, todo está bajo licencia BSD por lo que puede ser usado en proyectos propietarios sin ningún problema.

Puedes ver la página de la librería o ir a la página de patrones en donde encontrarás trucos sobre cómo hacer drag&drop, autocompletado, … y que, según indican, irán ampliando mes a mes. Por último te puedes dar una vuelta por el blog oficial donde sacarán más información acerca de todo este sistema.


« Artículos anteriores