Cita del Día

Sobre estas líneas se debería ver (¿funciona?) mi último proyecto: la Cita del Día para Blogger. De hecho, debería poder instalarse en cualquier sitio. Sólo necesita que JQuery esté disponible en la página, aunque sería bastante fácil reescribir el código para eliminar la dependencia. Las citas están publicadas en una hoja de cálculo de Google Spreadsheets.

[¡Peligro! ¡Palabrería informática!] El protocolo implementado por las APIs de GData, como extensión de Atom, permite manipular documentos de todo pelaje alojados en los múltiples servicios de Google. Una pequeña adición, la posibilidad de disponer de los resultados en formato JSON, y más concretamente, como JSON evaluado en un script, permite superar gran parte de las limitaciones de seguridad impuestas por los navegadores sobre Ajax. Es posible así realizar cross-site scripting, incorporando contenidos de documentos disponibles mediante feeds de GData en páginas web, sin disponer de control sobre el servidor.

Necesitamos una hoja de cálculo publicada con dos columnas (citas y autores).

http://spreadsheets.google.com/pub?key=pK3d1irR7cVxUSt9KBb8GFw&output=html&gid=0&single=true&range=A1:B4

Un pequeño script permitirá extraer el contenido de esta hoja conociendo algunos de sus datos:

  • Su clave de publicación (key).
  • El identificador único de la página a publicar (una hoja puede tener varias páginas).
  • El rango de celdas del que se va a extraer la información.

Esos datos pueden obtenerse a partir de la URL de publicación de feeds que aparece en las “opciones adicionales de publicación” de la pestaña “Publicación” de una hoja de cálculo. Armados con la información apropiada, podemos programar algo interesante:

var CiteSpreadsheet = {
    'rows': 159,
    'getJsonUrl': function(idx) {
        var baseSpreadsheet = 'http://spreadsheets.google.com/feeds/';
        var feedType = 'cells/';
        var key = 'o06661241339204957995.1659223542184495700/';
        var sheetId = 'od6/';
        var feedAccess = 'public/basic?';
        var range = 'range=A' + idx + ":B" + idx;
        var output = '&alt=json-in-script';
        var callback = '&callback=CiteSpreadsheet.processJsonResponse';
        return baseSpreadsheet + feedType + key + sheetId + feedAccess + range + output + callback;
    },
    'createScriptElem': function(url) {
        var html = '<script type="text/javascript" src="' + url + '"></script>';
        $(html).appendTo('body');
    },
    'getIndex': function() {
        var today = new Date();
        var startDate = new Date(today.getYear(), 0, 1);
        var delta = today.getTime() - startDate.getTime();
        var dayOfYear = Math.ceil(delta / 86400000);
        return dayOfYear % CiteSpreadsheet.rows;
    },
    'processJsonResponse': function(jsonData) {
        var retrievedContent = "<span>" + jsonData.feed.entry[0].content.$t +
            " <cite>" + jsonData.feed.entry[1].content.$t + "</cite></span>";
        $(".cite").append(retrievedContent);
    }
};

CiteSpreadsheet.createScriptElem(
    CiteSpreadsheet.getJsonUrl(
        CiteSpreadsheet.getIndex()));

El objeto del código es insertar, dinámicamente, una marca <script> en el documento actual, que apunte mediante su atributo src a una URL específica de consulta válida para la hoja de cálculo deseada, con formato de salida json-in-script, lo que devuelve un script listo para ejecutar con los datos pedidos en un objeto (en el enlace anterior se describe su estructura; Firefox, Firebug y un punto de ruptura ayudan considerablemente).

El feed obtenido ofrecerá información sobre celdas concretas de la hoja en el rango An:Bn, donde n es el número de fila deseado. Como en la hoja hay 159 citas, para dar una diferente cada día calculamos el índice como el número del día actual dentro del año módulo el total de filas.

Por último, para incorporar la cita al DOM de la página, necesitamos un elemento al que anclarlo. Para ello, se incluye en la plantilla de la bitácora, en el lugar donde deba aparecer la cita, un módulo HTML/Javascript con el contenido

<span class="cite"/>

(podría valer un <div>). En otras plataformas de blogging esto se podrá hacer editando directamente la plantilla o de algún otro modo.

Anuncios

Quote of the Day

You should see over these lines the result of my last project: a Quote of the Day implementation for Blogger It should be a piece of cake to port to other blogging platforms: the only requirement for the code to work is to have a recent version of the JQuery Javascript library loaded. Rewriting the code to eliminate that dependency should also be easy. Quips are published on Google Spreadsheets.

[Warning! Buzzword-enabled text ahead!] GData APIs implement an Atom extension that enables remote document querying and editing. What’s more, query results can be obtained as evaluated JSON objects; this technique allows to bypass most cross-site scripting security constraints, so Ajax widgets can be implemented without control over the server side.

We will need a published spreadsheet sporting quips and authors in two columns.

http://spreadsheets.google.com/pub?key=pK3d1irR7cVxUSt9KBb8GFw&output=html&gid=0&single=true&range=A1:B4

A tiny little script will get us the sheet’s contents. We only have to look for these pieces of information in order to make it work:

  • Publishing key.
  • Unique identifier for the desired sheet (a spreadsheet is organized as a book, so it can contain several sheets).
  • Desired cell range.

These can be obtained from the feed publishing URL that appears in Publish/More publishing options in the Google Spreadsheets interface. There goes the script:

var CiteSpreadsheet = {
    'rows': 159,
    'getJsonUrl': function(idx) {
        var baseSpreadsheet = 'http://spreadsheets.google.com/feeds/';
        var feedType = 'cells/';
        var key = 'o06661241339204957995.1659223542184495700/';
        var sheetId = 'od6/';
        var feedAccess = 'public/basic?';
        var range = 'range=A' + idx + ":B" + idx;
        var output = '&alt=json-in-script';
        var callback = '&callback=CiteSpreadsheet.processJsonResponse';
        return baseSpreadsheet + feedType + key + sheetId + feedAccess + range + output + callback;
    },
    'createScriptElem': function(url) {
        var html = '<script type="text/javascript" src="' + url + '"></script>';
        $(html).appendTo('body');
    },
    'getIndex': function() {
        var today = new Date();
        var startDate = new Date(today.getYear(), 0, 1);
        var delta = today.getTime() - startDate.getTime();
        var dayOfYear = Math.ceil(delta / 86400000);
        return dayOfYear % CiteSpreadsheet.rows;
    },
    'processJsonResponse': function(jsonData) {
        var retrievedContent = "<span>" + jsonData.feed.entry[0].content.$t +
            " <cite>" + jsonData.feed.entry[1].content.$t + "</cite></span>";
        $(".cite").append(retrievedContent);
    }
};

CiteSpreadsheet.createScriptElem(
    CiteSpreadsheet.getJsonUrl(
        CiteSpreadsheet.getIndex()));

What the code does, in short, is dynamically inserting a <script> tag in the document, with its src attribute pointing to a specific query URL for the spreadsheet. Output format should be json-in-script; this returns a ready-to-execute script that wraps data in a Javascript object. Its general format is described in the previous link, but Firefox, Firebug and a judicious break point go all the way to get a hold on the gory details.

We’ve got a feed with information about certain cells (range An:Bn, where n is a row index). As the sheet contains 159 quotations, in order to provide a different one daily we compute that row index as the current day in year modulus total number of rows.

Last but not least, we need a hook; someplace in the blog template to anchor the newly retrieved content. We do so by adding to the template an HTML/Javascript module where we want our quip to appear. Its contents should be, at the very least,

<span class="cite"/>

(a <div> would also work —in fact, any container element with class cite). For other blogging platforms the same effect could be achieved by directly editing the template, or by some other means which I leave as exercise for the reader.

Comprime tu código

A pesar de que el ancho de banda disponible para usuarios finales crece sin medida (sobre todo fuera de esta esquinita suroccidental de la Península Europea), sigue siendo un buen consejo optimizar en lo posible el código Javascript de una página web. Es razonable porque los scripts son componentes de la página que contribuyen a la interactividad, prestan servicios variopintos y, con un poco de suerte, funcionan; pero son invisibles. Los usuarios no perciben la necesidad de unos segundos adicionales de descarga, si hay suerte y no tenemos la wifi pillada por algún vecino (o vecina), a cambio de un efecto especial en los botones o de una ensalada de menús dinámicos.

Por eso sigue siendo interesante comprimir el código. La herramienta que he usado para mis últimas creaciones es /packer/ con la opción de codificación Base62. Antes de usar esta herramienta, parece recomendable pasar los scripts candidatos a revoltillos alfanuméricos por un “limpiador” como JSLint.

¿Por qué este paso adicional? Sencillo. Javascript, pese a que su nombre lo liga a un lenguaje serio y formal (algunos dirían sadomaso o bondage) como es Java, es en realidad una de esas creaciones calenturientas y flexibles que, sin llegar al límite de Perl, lenguaje en el que un mono pisoteando un teclado puede escribir un programa ejecutable, permite gran cantidad de licencias de sintaxis. Licencias que, ante cualquier manipulación automática del código (como por ejemplo, la compresión), se vuelven contra el despistado programador y se lo comen. Con patatas.

JSLint sirve para detectar, con diferentes grados de rigurosidad (alto, altísimo e ionosférico), los potenciales problemas que un programa en Javascript puede desarrollar por mor de su sintaxis. Un caso claro: los puntos y coma, o falta de ellos, al final de cada sentencia. Es recomendable escribir cualquier programa candidato a la compresión de forma ordenada, con puntos y coma en los sitios correctos, llaves en los bloques, uso adecuado del cualificador var, uso moderado de eval()… Y así sucesivamente. La documentación de JSLint ofrece más pistas, pero las que he citado serán suficientes para mantener al 99,9% de los scripts libres de problemas.

Por si las moscas, ¡no borres la versión descomprimida! Aunque las moscas no son el único motivo: también están la depuración sana, y no menos importante, la contribución a la comunidad. La seguridad por la obscuridad no es manera de proteger código: cualquiera que desee robar esos algoritmos patentados en Javascript podrá hacerlo con un mínimo de esfuerzo, por mucho que ofusquemos el código. Acepta un consejo: si de veras necesitas el velo del secreto, no programes en Javascript, punto. Internet no funciona así.

Bibliolinks v3

Lately, real life constraints have forced me to consider the possibility of growing an additional pair of arms, Shiva-style; however, some tiny bugs in Bibliolinks, together with my recent discovery of jQuery, have prompted me to release a new version, Bibliolinks v3.

This version features a new, web-two-dot-zeroish load progress indicator, together with a handy link to open all URLs at once, and will exclude all self-links from the list (they weren’t that useful, anyway). You could have a look at my original article for installation details, or just read the documentation (Yes! This time the code is slightly documented!); but as there are subtle changes, I’ll post here a short guide:

  1. Obtain a Google AJAX Search API key.
  2. Edit your template and add this code snippet just before the </head> tag:
    <link href='http://www.google.com/uds/css/gsearch.css' rel='stylesheet' type='text/css'/>
    <link href='http://brucknerite.googlepages.com/bibliolinks.css' rel='stylesheet' type='text/css'/>

    Download this stylesheet here.

  3. Save your template, click on the Expand Widget Templates box and look for some place inside your post footer to drop this code snippet:
    <a class='bibliolink' expr:name='"bibliolink" + data:post.id' style='display:none;cursor:pointer;'/>

    In my template, there is a <div class='post-footer'>, but YMMV.

  4. Finally, add links for two scripts. The best place to do so is just before the closing </body> tag:
    <script src='http://www.google.com/uds/api?file=uds.js&v=1.0&key=YOUR_KEY_HERE' type='text/javascript'/>
    <script src='http://brucknerite.googlepages.com/bibliolinks3.js' type='text/javascript'/>

    Don’t forget to substitute YOUR_KEY_HERE by your very own API key.

And that’s all. Wonder why I skipped v2? Me too. There are stranger version numberings over there, you know.

Código elegante

Una herramienta recomendable para todo aquél que planee mostrar código en una bitácora es dp.SyntaxHighlighter. Éste es el modo de incorporarlo en Blogger:

  1. Descarga la última versión disponible de dp.SyntaxHighlighter (1.4.1).
  2. Descomprime el paquete en algún lugar de tu disco duro. Hay algunos ejemplos de uso, y dos directorios importantes: Scripts y Styles. Necesitas alojar en algún lugar accesible la hoja de estilos CSS SyntaxHighlighter.css, el script shCore.js y tantos “brushes” como planees utilizar. Cada brush es un pequeño script adicional que proporciona soporte para un lenguaje de programación. Los lenguajes soportados son C++, C#, CSS, Delphi, Java, Javascript, PHP, Python, Ruby, SQL, Visual Basic y XML (HTML, XHTML… se consideran dialectos).
  3. Edita tu plantilla de Blogger (¡haz copias de seguridad primero!) En primer lugar, añade la referencia a la hoja de estilos dentro del la cabecera de la página (por ejemplo, justo antes de </head>). Así:<link type=’text/css’ rel=’stylesheet’ href=’SyntaxHighlighter.css’/>
  4. Edita el cuerpo de la plantilla para poner el código que sigue antes de </body>.<script type=’text/javascript’ src=’shCore.js’/>
    <script type=’text/javascript’ src=’shBrushJScript.js’/>
    <script type=’text/javascript’ src=’shBrushJava.js’/>
    <script type=’text/javascript’ src=’shBrushCss.js’/>
    <script type=’text/javascript’ src=’Scripts/shBrushXml.js’/>
    <script type=’text/javascript’>//<![CDATA[
    dp.SyntaxHighlighter.HighlightAll(‘code’);
    //]]></script>He escogido ese conjunto de brushes, pero puedes poner cualquier otro.
  5. Ya hemos terminado con la infraestructura. Ahora, sólo es necesario incorporar código para mostrar el nuevo juguetito de nuestra bitácora. Eso es muy fácil: basta con añadir el código dentro de una marca <textarea>, con los siguientes atributos:<textarea name=”code” class=”nombre_de_lenguaje:modificadores”>
    …código a mostrar…
    </textarea>El atributo name cualifica al área de texto para ser modificada dinámicamente por el script dp.SyntaxHighlighter. class determina el lenguaje y ciertos modificadores de comportamiento, expresados como pseudoclases de CSS. Estos son los detalles adicionales.

Algún consejo: es interesante aplicar los atributos rows y cols al elemento <textarea>. Esto es así por robustez: si no llegaran a funcionar los scripts (normalmente debido a un fallo transitorio de red, a que el usuario tiene desactivada la ejecución de Javascript o a que se está leyendo el artículo fuera del contexto de un navegador —por ejemplo, a través de un lector RSS) el código se vería de todos modos.

Y para el final, los problemas.

  • Los saltos de línea son un problema con el editor de Blogger. La única solución que he encontrado pasa por desactivar la conversión automática de saltos de línea en elementos <br/>. Mira aquí.
  • Si estás introduciendo XML o cualquier variante (HTML, por ejemplo), es recomendable proteger el primer caracter de las marcas (el signo <), que debería aparecer, literalmente, como &lt;. Esto no afectará a la presentación del código, ni a la ventana de “vista simple” proporcionada por el script.

Bibliolinks explained

In an earlier post I presented bibliolinks, a new blogger tool based on Google AJAX Search API. Now it’s time to explain how to install it in your Blogger blogs. You’ll have to modify your template in obscure and contorted ways, so be prepared and backup it before it’s too late! One more thing: this procedure works with my own template, on Firefox 2. I will not be held responsible of anything if you are not me, fiddling with my own template on my own setup. Even if you were me (and I am me, unless…) I wouldn’t bet on any accountability.

Aren’t you scared yet? Ready? There we go. First of all, you have to register for a Google AJAX Search API key here. Got it? Save it somewhere! (You can always regenerate it later; the key is calculated from the URL you input, in this case, you blog’s address.)

Now, edit your template and add this snippet just before your closing </head> tag:

<link href='http://www.google.com/uds/css/gsearch.css' rel='stylesheet' type='text/css'/>

We are not even close to finish yet! Save your template, click on the Expand Widget Templates box and look for some place to drop this code snippet:

<a class='bibliolink' expr:name='"bibliolink" + data:post.id' style='display:none;cursor:pointer;'>Bibliolink <span></span></a>

This should be located somewhere inside your post footer container (on my template, it’s a <div class='post-footer'> tag). I decided to put it inside an empty element denoting a third line of content for post footers, exactly here:

<p class='post-footer-line post-footer-line-3'/>

YMMV, of course. Now, only one more step: you have to provide a link for two scripts. The best place to do so is just before the closing </body> tag. This is the first script, for Google AJAX Search functions:

<script src='http://www.google.com/uds/api?file=uds.js&amp;v=1.0&key=YOUR_KEY_HERE' type='text/javascript'/>

Don’t forget to substitute YOUR_KEY_HERE by your own API key. Immediately next to that script, add this one:

<script language='Javascript' src='http://brucknerite.googlepages.com/bibliolinks.js' type='text/javascript'/>

Here you should use your own hosting for the code, since I’m using my own Google Page. Here is a link to an uncompressed (and, for now, uncommented) version of the code.

And that’s all for now!

Bibliolinks!

Lots of links in your posts? Would you like something that provides your readers with prompt access to all links in your posts, together with clipped content? Something like an automatic bibliography for your blog? You’ve come to the right place!

Bibliolinks is a tool which, by means of some right out nasty manipulation of DOM and a tiny little speck of magic powder in the form of Google AJAX Search API, allow readers to have access to a compilation of all links in a post. It’s alpha quality, so don’t expect to have an easily deployed widget soon. In fact, you should not expect it at all, since the level of slicing and dicing necessary for Blogger templates in order to display bibliolinks is rather high, and I don’t see that diminishing any time soon.

I’ll post an installation tutorial and some code as soon as I find some time to refine the implementation. Meanwhile, enjoy them! (Or crash your browser, whichever comes first.)