Máquinas virtuales para Internet Explorer

En cualquier desarrollo web hay que comprobar que se ve correctamente en todos los navegadores. Si usamos GNU Linux no tenemos el Internet Explorer, así que debemos ingeniárnoslas para hacer las pruebas.

La misma gente de Microsoft nos lo pone muy fácil: han creado una página desde donde se pueden descargar ficheros para máquinas virtuales que tienen las versiones de Internet Explorer desde la 6 a la 11. Basta con instalarse  VirtualBox y descargar estas máquinas virtuales para poder hacer pruebas con todas las versiones de Internet Explorer que queramos.

Este es el enlace para la descarga: https://modern.ie/en-us/virtualization-tools#downloads

Posicionar de forma absoluta elementos dentro de celdas en Firefox

Una nota rápida para no tirarme media hora en el futuro sufriendo por esto…

Firefox tiene un bug muy curioso: si intentamos posicionar elementos de forma absoluta dentro de una celda (ya sea una celda de tabla normal o un div con estilo display:table-cell) él amablemente nos enseña el dedo más largo de su peluda patita y los coloca con respecto al primer elemento de fuera de la tabla.

Para evitarlo hay que crear como primer hijo de la celda un div con posición relativa que ocupe todo el ancho y alto de la celda, y meter dentro de él los elementos que queramos posicionar de forma absoluta. Entonces sí funciona.

Redirigir al usuario y continuar trabajando en PHP

Hay veces en las que debemos realizar alguna tarea con PHP que lleva demasiado tiempo (convertir imágenes, videos, etc…). En estos casos no es elegante dejar esperando al usuario, es preferible redirigirle a una página donde se le informe de que se está llevando a cabo la tarea.

Una solución podría ser implementar un sistema de workers que realicen el trabajo; así nuestro script de PHP simplemente tendría que lanzar el trabajo y terminaría inmediatamente. Esta es la mejor solución porque los sistemas de workers permiten un escalado horizontal.

Pero hay ocasiones en las que por las características de nuestro proyecto no se pueden o no se quieren implementar estos workers. En estos casos nos bastará con redirigir al usuario a una página informativa y realizar el trabajo desde nuestro script de PHP.

Esta técnica la encontré, y está perfectamente documentada, en esta página, que podéis consultar para una explicación detallada. Aquí me limito a copiar el código:

    //Redirect to messageToUser.php
    header("Location: messageToUser.php");
    //Erase the output buffer
    ob_end_clean();
    //Tell the browser that the connection's closed
    header("Connection: close");

    //Ignore the user's abort (which we caused with the redirect).
    ignore_user_abort(true);

    //Extend time limit to 30 minutes
    set_time_limit(1800);
    //Extend memory limit to 10MB
    ini_set("memory_limit","10M");
    //Start output buffering again
    ob_start();

    //Tell the browser we're serious... there's really
    //nothing else to receive from this page.
    header("Content-Length: 0");

    //Send the output buffer and turn output buffering off.
    ob_end_flush();
    //Yes... flush again.
    flush();

    //Close the session.
    session_write_close();

    //Do some work

    //Then notify the user that it's finished

Actualización 14/09/2021: si usamos PHP-FPM hay una función que nos permite cerrar la conexión con el navegador y seguir haciendo lo que queramos en nuestro código, fastcgi_finish_request.

Enlaces en páginas web sin especificar protocolo

Últimamente he estado viendo en bastantes sitios que los enlaces a documentos externos se escriben sin especificar el protocolo. Es decir, en lugar de escribir

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

escribiríamos esto

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

Así a bote pronto me ha chocado un poco, porque de toda la vida yo pensaba que era el http:// lo que distinguía a un enlace externo de uno que hacía referencia a un documento dentro del árbol de ficheros de nuestra página.

Pero por lo visto resulta que es el // lo que hace que el navegador interprete el enlace como externo, por lo que nos podemos ahorrar el http o https en la URL siempre que queramos que el enlace use el protocolo http y no otros como ftp, mailto, o tel.

Además tenemos una ventaja añadida si quitamos el protocolo: el navegador usará el protocolo que esté usando la página en la que está el enlace. Si hemos accedido a ella mediante http usará http, y si hemos accedido mediante https usará https. Esto significa que si estamos cargando un fichero con http (contenido no seguro) en una página cargada con https (contenido seguro) el navegador no protestará (que yo recuerde esto solamente lo hace Internet Explorer).

Actualización del 17/11/2015: no es solo Internet Explorer, otros navegadores también bloquean por ejemplo ficheros de JS cargados desde una URL no segura si se ha accedido a la página a través de una URL segura. Un motivo más para usar esta forma de escribir las URL.

Extensión Google Chrome para videos de YouTube que se cuelgan esperando a clickberry.tv

Antes de cambiar de ordenador utilizaba Ubuntu 12.10 32 bits y me pasaba una cosa muy extraña: en muchas páginas había incrustados videos de YouTube que no podía ver; el navegador Google Chrome se quedaba mostrando el mensaje “Esperando a clickberry.tv” durante un buen rato y finalmente mostraba un mensaje de error en el vídeo.

Al cambiar el ordenador e instalar Ubuntu 13.10 64 bits pensaba que el problema se solucionaría pero resulta que no, me sigue pasando lo mismo. Después de mucho buscar en Google no he encontrado ninguna solución, ni siquiera he podido encontrar referencias de que esto le pase a alguien más.

Como el problema era bastante molesto decidí investigar las extensiones de Chrome para intentar solucionar el asunto. Resulta que las extensiones son simplemente HTML, CSS y JS, así que resulta muy sencillo hacer una. Este es el código JS que soluciona el problema:

$(document).find("iframe").each(function()
{
	var src = $(this).attr("src");

	if (src.indexOf("youtube.com/embed") > -1)
	{
		var code = src.split("/embed/")[1].split("?")[0];
		var button = $(document.createElement("div"));
		button.addClass("button");
		button.html(chrome.i18n.getMessage("button_caption"));
		button.click(function()
		{
			window.open("http://www.youtube.com/watch?v=" + code);
		});
		button.insertBefore($(this));
	}
});

Realmente no soluciona el problema, el video incrustado sigue esperando a clickberry.tv, pero la extensión añade un botón encima que abre el video en la página de YouTube, donde se ve sin problemas.

La extensión está disponible de forma gratuita en la Chrome Web Store.

Enviar paquetes UDP desde línea de comandos

Estoy haciendo un programa para poder hacer una consola tipo Firebug pero para código PHP, y la idea es que el PHP envíe datos a esa consola mediante UDP. He empezado a hacer el programa y para hacer pruebas rápidas del servidor necesitaba enviar paquetes UDP. La solución más sencilla es un programa que se llama sendip, que permite enviar paquetes de distintos tipos a cualquier destino.

Para instalarlo en Ubuntu:

sudo apt-get install sendip

Una vez instalado, el uso es muy sencillo:

sudo sendip -p ipv4 -p udp -is 192.168.0.199 -us 5000 -ud 1947 -d "Soy un paquete udp" localhost

Los parámetros son estos:

  • -p ipv4: le indica al programa que usaremos  ipV4.
  • -p udp: le indica al programa que usaremos UDP.
  • -is 192.168.0.199: es la dirección IP de origen del paquete.
  • -us 5000: puerto de origen.
  • -ud 1947: puerto de destino.
  • -d “Soy un paquete udp”: los datos a enviar.
  • localhost: el host al que enviaremos el paquete.

Minimizador de JS y CSS

En las páginas que están en producción es conveniente minimizar el código JavaScript y el CSS para que pesen menos y ayuden a que la velocidad de carga de la página sea rápida. Si bien los navegadores cachean estos ficheros y esto solamente se aplica a la primera carga siempre conviene que sea lo más rápida posible (además de reducir el ancho de banda que consumimos en nuestro servidor).

Hay muchos minimizadores de código JavaScript y de CSS, yo uso JavaScript Minifier simplemente porque tiene un enlace en la misma página a su minimizador de CSS, y hace todo el proceso más rápido.

Plugin de jQuery para animaciones

Aunque sé perfectamente que tiene que haber mil plugins que hagan esto me he permitido reinventar la rueda porque nunca había hecho un plugin de jQuery y ya tocaba.

Como el formato MNG aún no está soportado en todos los navegadores hay que buscarse las castañas para hacer animaciones con imágenes que llevan transparencia alpha, Este plugin lo que hace es coger una imagen que tiene todos los fotogramas de la animación uno encima del otro, y lo pone como imagen de fondo de un div, cambiando periódicamente la posición de la imagen de fondo para hacer el efecto de animación.

/*
Plugin para animaciones
v1.0
============================================================

Este plugin está pensado para poder tener animaciones tipo GIF pero con
imágenes PNG con transparencia alpha.

Utiliza una imagen en la que los frames están colocados uno encima del otro.
El plugin va cambiando la posición de la imagen de fondo del div para hacer el
efecto de animación.

USO: 

Se crea un div con estos atributos:

* data-spriteImg: URL de la imagen que contiene los frames
* data-numSteps: número de frames en la imagen

Se llama a la función animPic en el div pasando como variable el intervalo
de tiempo entre frames (en milisegundos), que por defecto es 1000.

$("#nuestroDiv").animPic({timeStep: 1000});

============================================================
*/
(function($)
{
    $.fn.animPic = function(options)
    {
        var defaults =
        {
            timeStep  : 1000 // Tiempo entre cambios de imagen (milisegundos)
        };

        options = $.extend(defaults, options);
        if (!this)
            return false;

        return this.each(function()
        {
            var obj;
            var height;
            var spriteimg;
            var numSteps;
            var currentStep = 0;

            obj = $(this);
            spriteImg = obj.attr('data-spriteImg');
            numSteps = obj.attr('data-numSteps');

            var i = $(document.createElement("img"));
            i.load(function()
            {
                height = this.height / numSteps;
                obj.css("width", this.width + "px");
                obj.css("height", height + "px");
                obj.css("background-position", "0 0");
                obj.css("background-image", "url('" + this.src + "')");

                setInterval(function()
                {
                    ++currentStep;
                    if (currentStep == numSteps)
                        currentStep = 0;
                    obj.css("background-position", "0 -" + (currentStep * height) + "px");
                }, options.timeStep);
            });
            i.attr("src", spriteImg);
        });
    };
}(jQuery));

CKEditor: forzar pegado como texto plano

El CKEditor es el editor de textos WYSIWYG para web que más me gusta, funciona estupendamente y tiene una API muy intuitiva.

Lo uso siempre que en un gestor de contenidos hay que poder editar texto dando un cierto formato, metiendo imágenes, tablas, etc… El problema suele venir cuando los clientes, al usarlo, copian y pegan de programas como Word, que mete su propio código HTML y cambia fuentes, tamaños de letra, espacios. Al final el contenido acaba quedando horroroso.

Pero nos podemos evitar estos dolores de cabeza con una opción de configuración muy sencilla:

config.forcePasteAsPlainText = true;

Simplemente añadiendo esta línea cualquier texto que se pegue se pegará como texto plano, librándonos de cualquier formato que pudiera tener el texto original y respetando el estilo de nuestra página.

Diodon: un histórico para el portapapeles

Hoy quiero hablar de uno de esos pequeños programas que cuando se usan por primera vez se pregunta uno dónde han estado toda nuestra vida. Es el equivalente en software de ver por primera vez a Anna Torv o a Claudia Longarte.

Esta joya se llama Diodon, y básicamente lo que hace es ir guardando en un buffer todo lo que copiamos al portapapeles, hasta un máximo de 100 entradas (tanto de texto como de imágenes). Cuando pulsemos la combinación de teclas que le hayamos asignado nos mostrará un menú contextual con todas esas entradas y con el cursor podremos movernos por ellas; al pulsar Enter sobre cualquiera nos la pega en el documento.

Yo lo tengo configurado para 25 entradas, es más que de sobra, y como combinación de teclas CTRL-SHIFT-Z. Ahorra mucho tiempo, porque permite por ejemplo seleccionar varios textos de un documento uno por uno y pegarlos después rápidamente en otro documento, sin tener que andar cambiando de uno a otro.

Además el icono que pone al lado del reloj es de una especie de pez globo inflado muy gracioso.

¿Cómo instalarlo en Ubuntu? Con tres líneas lo tendremos:

sudo add-apt-repository ppa:diodon-team/stable
sudo apt-get update
sudo apt-get install diodon

Actualización del 18/01/2015: he instalado Linux Mint y por algún motivo Diodon no funciona, no aparece el menú con el histórico del portapapeles al pulsar la combinación de teclas. He instalado una alternativa que se llama clipit y que funciona estupendamente.