Archivo para la categoría ‘Web’

Función en Javascript para filtrar filas de una tabla

Como en la entrada anterior de Javascrip para crear solapas, para filtrar las filas de una tabla también existen multitud de ejemplos en la Web, incluidos plug-ins de jQuery.

Pero como a mi me gusta experimentar para aprender, aquí está mi versión del filtrado de filas de una tabla. De momento no es plug-in de jQuery pero, como la vez anterior, no creo que sea demasiado difícil adaptarlo. Y, por supuesto que tiene sus fallos, pero se irán subsanando con el tiempo.

function tablefilter(table_selector, input_selector, search_level, colspan) {
	var table = $(table_selector);
	if(table.length == 0)
		return;

	var input = $(input_selector);
	if(input.length == 0)
		return;

	if(search_level == "undefined" || search_level < 1)
		search_level = 3;

	if(colspan == "undefined" || colspan < 0)
		colspan = 2;

	$(input).val("Buscar…");

	$(input).focus(function() {
		if($(this).val() == "Buscar…") {
			$(this).val("");
		}
		$(this).select();
	});

	$(input).blur(function() {
		if($(this).val() == "") {
			$(this).val("Buscar…");
		}
	});

	$(input).keyup(function() {
		if($(this).val().length >= search_level) {
			// Ocultamos las filas que no contienen el contenido del edit.
			$(table).find("tbody tr").not(":contains(\"" + $(this).val() + "\")").hide();
			
			// Si no hay resultados, lo indicamos.
			if($(table).find("tbody tr:visible").length == 0) {
				$(table).find("tbody:first").append('<tr id="noresults" class="aligncenter"><td colspan="' + colspan + '">Lo siento pero no hay resultados para la búsqueda indicada.</td></tr>');
			}
		} else {
			// Borramos la fila de que no hay resultados.
			$(table).find("tbody tr#noresults").remove();
			
			// Mostramos todas las filas.
			$(table).find("tbody tr").show();
		}
	});
}

Para hacerlo funcionar basta con llamar a la función con dos, tres o cuatro parámetros (a elegir; si no se pasan se usan los predeterminados). El primer parámetro es el selector de la tabla a aplicar; el segundo es el input que se usará para el filtro; el tercero es el número de caracteres mínimos para comenzar la búsqueda (si no se especifica se usan tres); y el cuarto es el número de columnas que se debe extender la fila de información. Un ejemplo de llamada sería:

$(document).ready(function() {
  tablefilter("table#mi_tabla", "table thead tr input#filtro", 2, 3);
});

Internamente esta función usa el método contains() de jQuery para buscar. Este método distingue entre mayúsculas y minúsculas, así que, para hacer mejores búsquedas, se puede indicar que este método no distinga de la siguiente forma:

jQuery.expr[':'].contains = function(a, i, m) { 
  return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0; 
};

En caso de que no funcione correctamente, se debe añadir exactamente lo mismo otra vez pero cambiando “.contains =” por “.Contains =“.

Y, cómo no, podéis ver un ejemplo del funcionamiento de la misma así como descargarlo.

Función en Javascript para crear solapas (tabs)

Existen multitud de snippets y plug-ins de jQuery para hacer solapas con diferentes partes de una misma página, pero ninguno de ellos con las características que he implementado en esta función (que —todavía— no es un plug-in de jQuery). La principal característica que quería conseguir era la simplicidad.

La mayoría de estos plug-ins o funciones requieren que se haga un poco de marcado en HTML para delimitar tanto el conjunto de solapas como cada una de ellas, con lo que, al menos, habrá que marcar un <div> general y un <div> por cada solapa.

Con esta función lo que se pretende, como he comentado antes, es que ese marcado adicional sea innecesario usando sólo lo que ya existe dentro de la página para crear las solapas.

Es por esto que esta función lo que hace es, dentro de una caja (o del cuerpo completo del HTML), convertir en solapa todo el contenido que hay entre diferentes encabezados del mismo nivel (<h1>..<h6>), es decir, si existe una página bien formada con sus correspondientes encabezados, mediante esta función es trivial mostrarla como solapas.

El código de la función —y, repito, no es un plug-in para jQuery pero no sería demasiado difícil adaptarla— es el siguiente:

function Tabs(element, tabElement) {
    // Si no existe la caja de donde coger los elementos, nos salimos.
    if($(element).length == 0)
        return;

    // Si ya las hemos creado, no lo volvemos a hacer. De momento sólo se soportan unas tabs por página.
    if($(element).find("ul#tabs").length > 0)
        return;

    // Creamos una lista con los elementos de las solapas (serán los botones).
    var tabList = $("<ul>", { id: "tabs" });

    // Cogemos lo que hay entre cada 'tabElement' y lo metemos en un div
    var counter = 1;
    $(element).find(tabElement).each(function() {

        // Creamos una solapa para cada elemento y asignamos el evento "click".
        $(tabList).append($("<li>", { text: $(this).html(), id: "tab_" + counter }).click(function() {
            // Cuando hacemos click en la solapa, quitamos la selección.
            $(element).find("ul#tabs li").removeClass("selected");
            $(this).addClass("selected");
            var id = $(this).attr("id").substring(4);   // de "tab_1" nos quedamos con "1".
            $(element).find("div.tab_content").removeClass("selected");
            $(element).find("div.tab_content#tab_content_" + id).addClass("selected");

            // Reemplazamos la URL para que se refleje el cambio y, si se recarga la página, se recargue en el sitio correcto.
            var newurl = window.location.pathname;
            newurl = newurl.substring(newurl.indexOf("#") + 1) + "#tab_" + id;
            window.location.replace(newurl);

            // Volvemos a la parte de arriba de la página para que no queden ocultas las solapas por culpa de Drupal y su barra de administrador.
            // Otra opción podría ser volver un poco, en lugar de al principio. Por ejemplo: $(document).scrollTop($(document).scrollTop() - 10);
            $(document).scrollTop(0);
        }));

        // Metemos lo que hay entre los 'tabElement' en un div.
        $(this).nextUntil(tabElement).wrapAll("<div class='tab_content' id='tab_content_" + counter + "'></div>");

        // Borramos el elemento.
        $(this).remove();

        // Estos divs se ocultan con CSS.
        counter++;
    });

    // Añadimos la lista al div principal (pasado como parámetro).
    $(element).prepend(tabList);

    // Obtenemos el fragment (o hash) de la URL.
    var hash = window.location.hash;

    // Obtenemos el número de tab que sabemos está detrás de "_".
    hash = hash.substring(hash.indexOf("_") + 1);

    // Mostramos la primera solapa con el primer contenido (div) si no hay fragment. Si hay fragment
    // mostramos el que toca según el mismo (el fragment es #tab_x donde x es el número de tab [1..n]).
    if(hash != "" && $(tabList).find("li#tab_" + hash).length != 0) {
        $(tabList).find("li#tab_" + hash).addClass("selected");
        $(element).find("div.tab_content#tab_content_" + hash).addClass("selected");
    } else {
        $(tabList).find("li:first").addClass("selected");
        $(element).find("div.tab_content:first").addClass("selected");
    }
}

Como las solapas se crean con una lista (<ul>), se debe poner un poco de CSS para que se adapte, igual que se debe poner CSS para ocultar las solapas que no están visibles (en lugar de hacerlo con el propio Javascript modificando los atributos directamente, prefiero hacerlo con CSS añadiendo y/o quitando clases). El CSS básico (con un poco de estilo gráfico también) es el siguiente:

ul#tabs {
    margin: 10px 0;
    padding: 0;
    border-bottom: 1px solid silver;
    line-height: 29px;
}

ul#tabs li {
    display: inline-block;
    margin: 0 0 -1px -1px;
    padding: 0 10px;
    cursor: pointer;
    border: 1px solid silver;
    background: #DDDDDD;
    color: gray;
}

ul#tabs li.selected {
    background: white;
    color: #444444;
}

ul#tabs li:hover {
    background: #EEEEEE;
}

div.tab_content {
    display: none;
}

div.tab_content.selected {
    display: block;
}

Podéis ver un ejemplo de su funcionamiento y también podéis descargarlo para vuestro uso y disfrute (sin olvidarse de la licencia, claro).

Actualización 2012-06-07: Antonio me comenta que en IE9 (cómo no) no se ven bien las solapas. La lista que hará las solapas, al tener el CSS inline-block para que se muestren en una sola fila pero no se corten las solapas por la mitad, no se interpreta bien, por lo que salen en una lista normal. La solución sería que floten dichas solapas a la izquierda (anulando todo lo anterior del inline-block), más o menos así:

ul#tabs { overflow: auto; }
ul#tabs li { float: left; }

Resumen de los puntos de control a tener en cuenta para cumplir con la especificación WCAG 1.0

La WCAG 1.0 es la primera versión de las recomendaciones del W3C para crear páginas Web accesibles.

Este es un resumen no exhaustivo de los puntos de verificación para cada una de las prioridades de esta recomendación:

Prioridad 1

  1. Provee un texto equivalente para cada elemento no textual.
  2. Asegúrate de que cada información dada por el color también está disponible sin él.
  3. Identifica claramente los cambios en el lenguaje natural (p.e. mediante captions).
  4. Organiza los documentos para que puedan ser leídos sin hojas de estilo.
  5. Asegúrate que los equivalentes del contenido dinámico son actualizados cuando lo hace este.
  6. Evita que la pantalla parpadee.
  7. Usa el lenguaje más claro posible para el contenido del sitio.
  8. Proporciona enlaces alternativos para cualquier mapa de imágenes.
  9. Provee mapas de imágenes en el lado del cliente en lugar de en el lado del servidor excepto cuando las regiones no puedan ser definidas con las formas disponibles.
  10. Para tablas de datos, identifica las cabeceras de filas y columnas.
  11. Para tablas de datos con más de un nivel lógico de cabeceras de filas y columnas utiliza etiquetado para asociar celdas de filas y celdas de columnas.
  12. Titula cada frame para facilitar la navegación.
  13. Asegúrate de que las páginas que usan elementos programados (applets, scripts…) son usables aunque estos estén desactivados. Si no es posible, proporciona una página alternativa con la misma información.
  14. Proporciona una descripción auditiva de la información importante de una presentación multimedia.
  15. Para cualquier presentación multimedia (película, animación…) sincronice alternativas equivalentes (subtítulos, descripciones auditivas…) con la presentación.
  16. Si después de todo el esfuerzo no es posible crear una página accesible, cree una página alternativa accesible usando la tecnología del W3C.

Prioridad 2

  1. Asegúrate de que las combinaciones de color de fondo y de primer plano tienen suficiente contraste (prioridad 2 para imágenes y prioridad 3 para texto).
  2. Siempre que exista etiquetado apropiado, usa este para transmitir información en lugar de imágenes.
  3. Crea documentos que validen contra las gramáticas formales publicadas.
  4. Usa hojas de estilo para controlar el diseño y la presentación.
  5. Usa unidades relativas en los atributos del lenguaje de marcado y de las hojas de estilo.
  6. Utiliza encabezados conforme a la norma para transmitir la estructura del documento.
  7. Etiqueta listas y elementos de lista correctamente.
  8. Etiqueta correctamente las citas.
  9. Asegúrate de que el contenido dinámico es accesible o proporciona una página alternativa.
  10. Evita que el contenido parpadee.
  11. No crees páginas que se autorrefresquen.
  12. No crees páginas que se redireccionen automáticamente. Configura el servidor para realizar esa tarea.
  13. No hagas que aparezcan ventanas emergentes y no cambies de ventana sin informar al usuario.
  14. Usa las tecnologías del W3C cuando estén disponibles y usa las últimas versiones cuando sean compatibles.
  15. Evita tecnologías obsoletas de la W3C.
  16. Divide grandes grupos de información en otros más pequeños y manejables.
  17. Identifica claramente el destino de cada enlace.
  18. Provee metadatos para añadir información semántica a las páginas.
  19. Provee información sobre el diseño principal del sitio (mapa del sitio, tabla de contenidos…).
  20. Usa los mecanismos de navegación de forma consistente.
  21. No uses tablas para maquetar a no ser que tenga sentido cuando se linealiza. Si no es así, provee una página alternativa.
  22. Si usas tablas para maquetar, no uses elementos de formato gráfico.
  23. Describe el propósito de cada frame y la relación entre ellas.
  24. Asegúrate de que las etiquetas asociadas a controles de formulario están correctamente posicionadas.
  25. Asocia etiquetas explícitamente a controles de formulario.
  26. Asegúrate de que los gestores de eventos en scripts y applets son independientes del dispositivo.
  27. Evita movimientos automáticos en las páginas o provee elementos para pararlos.
  28. Haz elementos programáticos (scripts y/o applets) compatibles con tecnologías de asistencia.
  29. Asegúrate de que los elementos con su propia interfaz funcionan de forma independiente del dispositivo.
  30. Para scripts crea manejadores de eventos lógicos en lugar de hacerlos dependientes del dispositivo.

Prioridad 3

  1. Especifica la expansión de cada abreviatura o acrónimo la primera vez que aparezca en el documento.
  2. Identifica el primer lenguaje natural del documento.
  3. Crea un orden lógico al recorrer los enlaces, los controles de formularios y los objetos.
  4. Provee accesos directos desde teclado para los enlaces, controles o grupos de controles de formulario más importantes.
  5. Hasta que los navegadores distingan los enlaces adyacentes, provee caracteres imprimibles entre ellos.
  6. Provee enlaces para que los usuarios obtengan los documentos de forma acorde a sus preferencias (idioma, tipo de contenido…).
  7. Provee barras de navegación y da acceso al sistema de navegación.
  8. Agrupa enlaces relacionados, identifica el grupo y provee un método para saltarse los grupos.
  9. Si existe la función de búsqueda, provee diferentes métodos acordes a los diferentes perfiles de usuario.
  10. Coloca información distintiva al comienzo de encabezados, párrafos, listas, etc.
  11. Provee información acerca de colecciones de elementos.
  12. Provee un método para saltar el ASCII Art.
  13. Complementa el texto con presentaciones gráficas o auditivas para mejorar la comprensión de la página.
  14. Crea una presentación de la página consistente en todas las páginas.
  15. Provee enlaces de texto redundantes para cada región de los mapas de imágenes.
  16. Provee resúmenes para las tablas.
  17. Provee abreviaturas para las cabeceras de las tablas.
  18. Provee texto lineal alternativo para todas las tablas con texto en columnas paralelas.
  19. Incluye texto predeterminado en controles vacíos.

Este resumen es una traducción/adaptación del original en inglés.

11 características que Twitter debería tener

Mucha gente usa Twitter, esa red social tan “rara” que sólo permite 140 caracteres en cada mensaje. Y quizás sea por eso su gran éxito a pesar de que sus características técnicas no han cambiado desde… bueno, casi desde que se creó. Por eso creo que, desde el punto de vista de un usuario (no de un desarrollador), Twitter necesita, al menos, que se implementen estas 11 características:

  1. Edición de tuits: Sería bueno poder editar los tuits, al menos durante un tiempo después de la publicación, para corregir, por ejemplo, faltas de ortografía. No sería bueno poder editarlos siempre ya que con la sucesivas ediciones podrías hacer totalmente incoherente la conversión con el resto de usuarios.
  2. Bloqueo de usuarios sin necesidad de dejar de seguirlos: ¿Sabéis eso de “te sigo por compromiso”? Pues eso. Además, he visto algunos tuits donde ya se demanda esta característica.
  3. Omisión de tuits en el timeline que contengan un determinado hashtag: No estaría demás que se pudiera, en el TL principal, omitir de forma automática los tuits que contengan algún hashtag determinado, por eso de ser, en ocasiones, bastante cansinos.
  4. Poder recuperar todos tus tuits: En caso de tener un cliente de Twitter que no sea el de Web (y creo que con el de Web también), sólo podrás recuperar tus 3000 últimos tuits. Aunque el resto siguen en la base de datos, su API no soporta recuperar más de esta cantidad.
  5. Posibilidad de copia de seguridad de tus tuits: No hay ninguna forma de recuperar todos tus tuits si no es con aplicaciones externas. Y a esto hay que aplicarle el límite del punto anterior. Twitter debería implementar una forma de hacer copia de seguridad de tus tuits.
  6. Respuesta pública: Posibilidad de responder a un tuit de forma pública (que lo vean todos los usuarios que te siguen en lugar de los usuarios que te siguen y los que siguen al que respondes) para así no tener que poner un carácter antes del nombre de quien estás respondiendo y tener que desaprovecharlo.
  7. Implementación de un sistema para “leer más tarde”: Yo, al menos, uso los favoritos como marcadores para leer luego. No tengo ningún tuit favorito, simplemente en mi cliente del móvil los marco (los que tienen imágenes, alguna URL…) para leer cuando esté en un ordenador o tablet. Recordemos las limitaciones de las pantallas pequeñas y, sobre todo, las limitaciones de las conexiones 3G.
  8. Formato del texto: Esta quizás sería la más rompedora con la filosofía de Twitter, pero ayudaría mucho a expresar justamente lo que queremos decir —“emociones” incluidas— con, al menos, negrita, cursiva y tachado.
  9. Enlaces contextualizados: Los enlaces deberían ir como en HTML, enlazando un texto en lugar de que vaya la URL directamente. El contexto es muy importante en la Web y Twitter está haciendo un esfuerzo enorme —entiendo que inconscientemente— para eliminarlo. Lo mismo que los acortadores URL, donde se pierde toda la semántica de las URLs amigables. Pero ese es otro tema.
  10. Estadísticas: Sería buena idea que se proporcionaran estadísticas —principalmente informativas— de uso de Twitter, tanto de los usuarios (tuits por día, horarios de tuiteo, retuits…) como generales (tuis diarios, tuits diarios por países, usuarios activos en tiempo real…).
  11. Avance automático en el cliente Web: En el cliente Web, cuando sale el aviso de que hay nuevos tuits, al hacer clic, la página debería avanzar automáticamente hasta el último que has leído. Además, en la nueva interfaz, se debería marcar de alguna forma el último tuit que has leído (en la antigua se hacía).

Y una característica extra, la duodécima: más caracteres. Aquí hay muchísima controversia. Quizás, como he dicho antes, el éxito de Twitter sea precisamente el de tener un número de caracteres limitados. Pero, al menos a mi, muchas más veces de las que me gustaría se me quedan muy cortos para escribir lo que quiero decir. Y a veces no soy capaz de hacerle caso al famoso mensaje “Tu Tweet contiene mas de 140 caracteres. Tendrás que ser más ingenioso.”.

No estoy diciendo que se ponga un número ilimitado (o muy grande) de caracteres como ocurre con Google+ o Facebook, pero sí alguno más, por ejemplo —por aventurarme con un número— 200; o, mejor, 256 (28, por eso de ser friki :tongue: ). Por ejemplo, las notas de Menéame tienen 1000 caracteres y creo que la mayoría de ellas no pasan ni de los 500, pero cuando hay algo más largo que decir, se puede hacer sin ningún problema.

Pero bueno, esta es sólo mi opinión. Y vosotros ¿qué opináis de estas 11 características que Twitter debería tener? ¿Alguna más? ¿Alguna menos?

Libros de Smashing Magazine

Libros de Smashing Magazine

Hace bastante tiempo que sigo la página de Smashing Magazine que versa sobre diseño gráfico y diseño de interfaces de usuario, principalmente para Web aunque se pueden aplicar a cualquier interfaz. Y, aunque sigo la página, tengo que reconocer que no leo todos los artículos debido a su extensión y mi falta de tiempo.

Pero como creo que es una página sumamente interesante, al ver que había salido el segundo libro recopilando sus artículos, y desconociendo que había un primero, me decidí a comprarlos gracias a su buena reputación y a todos los artículos que he leído y donde he aprendido unas cuantas cosas. Además, había una oferta donde vendían los dos ejemplares por 35 € (más gastos de envío).

Y aquí están: en el primer vistazo, ¡oh, sorpresa!, están en inglés… bueno, eso ya lo sabía. En un segundo vistazo tengo que decir que el contenido es similar al de la Web (no puedo asegurar que sea el mismo contenido literal, pero sí trata los mismos temas) por lo que se centrará en diseño de interfaces de usuario dedicadas a Web (aunque se pueden aplicar a muchas otras cosas) pasando por los colores, las tipografías, ubicación de información, usabilidad, optimización, etc.

En cuanto a los libros, el primero es A5 de tapa blanda con 311 páginas en hojas plastificadas (como en revista) e impresión a todo color, destacando la tipografía sans-serif.

El segundo es A5 de tapa dura con 355 páginas, también en hojas plastificadas y a todo color, destacando, esta vez, que la tipografía es serif.

En conclusión, la calidad de los libros es muy buena y la calidad del contenido de los libros, a falta de haberlos leído, presupongo que será también muy buena por el simple hecho de tener la reputación de Smashing Magazine. Eso sí, estos libros no son de literatura así que están destinados a un público minoritario que se dedique principalmente al diseño gráfico en general y al diseño Web en particular.

Optimizando sitios Web

Muy buen artículo de Ricardo Galli, el creador y mantenedor de Menéame, sobre cómo optimizar sitios Web.

Más o menos viene a decir:

  • Reducir al máximo tus CSS y Javascript; y no incluyas los que no necesites (o cárgalo más tarde).
  • Si es posible, carga los elementos bloqueantes (widgets,…) de forma paralela (hay muchas formas de hacerlo, por ejemplo usando iframes).
  • Maquetar de forma que se pueda ir “dibujando” la página antes de tener todo el HTML. Con esto se reducirá el tiempo de carga percibido por el usuario.
  • Usar dominios, no subdominios, diferentes para contenido estático.
  • Comprimir el HTML y usar sprites para las imágenes (siempre que dichos sprites no sean demasiado complejos).
  • Intercalar la generación del contenido con el envío, mandando antes las partes que primero se generan (como la cabecera) para ir “dibujando” la página en el menor tiempo posible.

De esto yo deduzco que el modelo MVC es una auténtica mierda a la hora de optimizar sitios Web: lo que hace es procesar todo y luego generar y enviar el HTML al usuario, que es justamente lo que dice Ricardo Galli que es lento y que lo que realmente reduce el tiempo de carga percibido por el usuario es dibujar la página cuanto antes, aunque todavía no se halla generado completamente.

Mira que cosas, todos poniendo al MVC como la panacea y resulta que las pruebas dicen otra cosa… ¡Ains!

De Netscape 4.5 a Chrome 5

Desde que salió Firefox 1.0 no he vuelto a usar otro navegador Web. Antes (mucho antes) fue Netscape 4.5 y luego, cuando este dejó de ser el mejor, fue Internet Explorer (no se exactamente qué versión, aunque supongo que la 5.5 y la 6).

Firefox fue “el navegador”. Lo primero que introdujo fue la navegación por pestañas. Acostumbrados a tener unas cuantas ventanas, esta característica hizo que tu escritorio estuviera más limpio, más ordenado. Luego vinieron los plugins, y ahí ya todo cambió. Eso de poder tener tus añadidos era impresionante. Sobre todo para temas de desarrollo.

En sucesivas versiones de Firefox, lo que principalmente se mejoró fue su gestión de recursos (siempre se acusó un alto consumo de memoria) y su adaptación a los estándares Web. A parte de esto no hubo muchas más características nuevas. Además, tampoco se esmeraron suficiente en el desarrollo de su motor de Javascript, SpiderMonkey/TraceMonkey, con lo que el uso extensivo de Javascript en la Web 2.0 no ha sido todo lo “gran experiencia del usuario” que debería.

Pero el tiempo pasa, la tecnología evoluciona y… salen nuevos navegadores, como Google Chrome, la incursión de Google en el software de clientes Web.

Chrome es un navegador basado en WebKit, es decir, el motor de renderizado del HTML no lo han hecho ellos, mientras que el motor de Javascript, V8, sí que lo han construido desde cero. Y es ahí donde realmente destacan, aparte, por supuesto, de su interfaz de usuario minimalista y funcional, su integración con Flash, su geolocalización, su WebGL,… en definitiva, muchas características de las que otros navegadores carecen.

Y es precisamente por esto, tanto su velocidad como su mayores “features” por lo que he cambiado (casi) definitivamente de navegador principal: de Firefox a Chrome.

Lo único que hecho de menos, principalmente para desarrollo, es un validador de HTML al estilo del HTML Validator de Firefox. Pero el resto de herramientas es bastante buena ya que cuenta con Web Developer y con Firebug (Lite, eso sí).

Pero como siempre, dejo la puerta abierta al próximo navegador Web. Si es mejor que Google Chrome, no dudaré ni un segundo en cambiarme ;) .

Mozilla Thunderbird 3 y el Locale

Icono de Mozilla Thunderbird 3

Ya me he actualizado a Mozilla Thuderbird 3 y, a parte de la nueva interfaz y que algunas cosas cambian de sitio y la forma de hacerlas, la experiencia es totalmente recomendable.

El único problema que he tenido… bueno, problema no, simplemente que no me gusta como está, es que ciertas cadenas de la traducción al español (la localización de la aplicación también conocido como Locale) vienen todas en minúsculas cuando a mi me gustan como el comienzo de frase, con la primera letra mayúscula.

Y como no puedo parar quieto, he buscado por los archivos de Thunderbird y he dado con una solución, a falta de que alguien lo cambie dentro del grupo de desarrollo o de traducción (que supongo no lo harán porque, como he dicho, no es que sea un problema).

El caso es que hay que ir al archivo C:\Archivos de programa\Mozilla Thunderbird\chrome\ y coger el archivo es-ES.jar y hacer una copia de seguridad. Luego se abre con el WinZIP, WinRAR o similares y se descomprime (recordemos que un .jar es un .zip con un formato de carpetas específico).

Una vez descomprimido, dentro de la carpeta locale\es-ES\messenger se abre el archivo msgHdrViewOverlay.dtd con un editor de texto y se cambian ahí todas las cadenas que queramos corregir teniendo cuidado de no alterar el formato del archivo ni de comernos ninguna comilla.

Luego se recomprime con el programa anterior en formato ZIP, que puede variar desde Sin compresión hasta La mejor; funcionará de cualquier forma. Después de comprimir se renombra a es-ES.jar y se sobrescribe la versión anterior de este archivo.

Se inicia el Thunderbird y todo debería haber funcionado sin problemas teniendo ya nuestras cadenas cambiadas. Si algo falla, siempre tendremos la copia de seguridad.

Y esto es todo. Supongo que no seréis tan tiquismiquis como yo y tampoco es que lo vayáis a hacer, pero aquí lo tenéis.

Tetris en primera persona

Gracias a un twitter de @pinano, he encontrado el mejor Tetris ever made: First Person Tetris.

First Person Tetris

Simplemente probadlo. Digamos que no es exactamente lo que estáis pensando ;) . Incluso tiene un modo noche que ya es para flipar.

¿Un buen anti-spam para WordPress?

¿Alguien sabe de algún widget anti-spam para WordPress que sea bueno y que no tenga que deshacer todo el theme para maquetarlo?

He probado un par de ellos de los que están en el Codex pero no me convence ninguno… también de esos que son invisibles, pero no funcionan. Y la verdad es que no tengo ganas de hacerme el mío propio. Si sabéis de alguno poned un comentario :) .

Wikipedia somos todos

Gracias, Wikipedia

Ya he comentado por aquí que la Wikipedia me parece el mejor proyecto de Internet, y con diferencia. Porque en la Wikipedia está mucho del conocimiento humano (no en profundidad, pero sí lo suficiente como para estar informado) y, además, es de todos. Todos podemos ampliarlo y todos podemos ampliar nuestros conocimientos gracias a ella. Así que yo he donado una pequeña cantidad para que siga ahí. Para que todos estemos ahí, porque la Wikipedia somos todos.

Por supuesto, con esto no gano nada, no es publicidad, no hay beneficio económico, es simplemente apoyo. ¿Y tú, has donado ya?

Manifiesto en defensa de los derechos fundamentales de Internet

Ante la inclusión en el Anteproyecto de Ley de Economía sostenible de modificaciones legislativas que afectan al libre ejercicio de las libertades de expresión, información y el derecho de acceso a la cultura a través de Internet, los periodistas, bloggers, usuarios, profesionales y creadores de Internet manifestamos nuestra firme oposición al proyecto, y declaramos que:

  1. Los derechos de autor no pueden situarse por encima de los derechos fundamentales de los ciudadanos, como el derecho a la privacidad, a la seguridad, a la presunción de inocencia, a la tutela judicial efectiva y a la libertad de expresión.
  2. La suspensión de derechos fundamentales es y debe seguir siendo competencia exclusiva del poder judicial. Ni un cierre sin sentencia. Este anteproyecto, en contra de lo establecido en el artículo 20.5 de la Constitución, pone en manos de un órgano no judicial —un organismo dependiente del Ministerio de Cultura—, la potestad de impedir a los ciudadanos españoles el acceso a cualquier página web.
  3. La nueva legislación creará inseguridad jurídica en todo el sector tecnológico español, perjudicando uno de los pocos campos de desarrollo y futuro de nuestra economía, entorpeciendo la creación de empresas, introduciendo trabas a la libre competencia y ralentizando su proyección internacional.
  4. La nueva legislación propuesta amenaza a los nuevos creadores y entorpece la creación cultural. Con Internet y los sucesivos avances tecnológicos se ha democratizado extraordinariamente la creación y emisión de contenidos de todo tipo, que ya no provienen prevalentemente de las industrias culturales tradicionales, sino de multitud de fuentes diferentes.
  5. Los autores, como todos los trabajadores, tienen derecho a vivir de su trabajo con nuevas ideas creativas, modelos de negocio y actividades asociadas a sus creaciones. Intentar sostener con cambios legislativos a una industria obsoleta que no sabe adaptarse a este nuevo entorno no es ni justo ni realista. Si su modelo de negocio se basaba en el control de las copias de las obras y en Internet no es posible sin vulnerar derechos fundamentales, deberían buscar otro modelo.
  6. Consideramos que las industrias culturales necesitan para sobrevivir alternativas modernas, eficaces, creíbles y asequibles y que se adecuen a los nuevos usos sociales, en lugar de limitaciones tan desproporcionadas como ineficaces para el fin que dicen perseguir.
  7. Internet debe funcionar de forma libre y sin interferencias políticas auspiciadas por sectores que pretenden perpetuar obsoletos modelos de negocio e imposibilitar que el saber humano siga siendo libre.
  8. Exigimos que el Gobierno garantice por ley la neutralidad de la Red en España, ante cualquier presión que pueda producirse, como marco para el desarrollo de una economía sostenible y realista de cara al futuro.
  9. Proponemos una verdadera reforma del derecho de propiedad intelectual orientada a su fin: devolver a la sociedad el conocimiento, promover el dominio público y limitar los abusos de las entidades gestoras.
  10. En democracia las leyes y sus modificaciones deben aprobarse tras el oportuno debate público y habiendo consultado previamente a todas las partes implicadas. No es de recibo que se realicen cambios legislativos que afectan a derechos fundamentales en una ley no orgánica y que versa sobre otra materia.

Este manifiesto, elaborado de forma conjunta por varias personas, es de todos y de ninguno. Si estás de acuerdo y quieres sumarte a él, difúndelo por Internet.

Yo lo vi en Barrapunto, en Microsiervos y en muchos otros sitios más. Porque eso sí que es un atentado contra nuestros derechos fundamentales. Y todo por dinero, como siempre. Por mantener un negocio de cuatro a costa de todos. Pero lo peor es que nuestro maravillos gobierno de izquierdas, legisladores para el pueblo, ha sucumbido ante las presiones de empresas privadas. Genial.

Clonar un objeto en Javascript

En Javascript las variables que apuntan a objetos son referencias, por lo que la asignación entre las mismas se hace de esta forma con lo que la modificación de una de estas variables afecta al resto de referencias. Por ejemplo:

var myObject = {
text: ‘Clonning Objects’
};

var mySecondObject = myObject;
mySecondObject.text = ‘Clonando Objectos’;

// saldrá una alerta con el texto ‘Clonando Objetos’ ya
// que las variables se asignan por referencia
alert(mySecondObject.text);

En el alert(...) saldrá el texto ‘Clonando Objetos’ ya que ambas variables apuntan a la misma zona de memoria, de ahí las referencias. Es debido a esto, y que en algunas ocasiones necesitas clonar un objeto, por lo que es necesario implementar una función que lo haga. Para ello tenemos esta función, que la he visto en StackOverflow aunque la he retocado un poco, que funciona perfectamente:

function clone(from) {
if(from == null || typeof from != “object”)
return from;

if(from.constructor != Object &&
from.constructor != Array)
return from;

if(from.constructor == Date ||
from.constructor == RegExp ||
from.constructor == Function ||
from.constructor == String ||
from.constructor == Number ||
from.constructor == Boolean)
return new from.constructor(from);

var to = {};
to = to || new from.constructor();

for (var name in from) {
to[name] = typeof to[name] == “undefined” ?
this.clone(from[name]) :
to[name];
}

return to;
}

Con esta función, el ejemplo anterior se convierte:

var myObject = {
text: ‘Clonning Objects’
};

var mySecondObject = clone(myObject);
mySecondObject.text = ‘Clonando Objectos’;

// saldrá una alerta con el texto ‘Clonning Objects’ ya que,
// aunque las variables se asignan por referencia, nuestra
// función ha clonado nuestro objecto con lo que son dos
// objetos distintos
alert(mySecondObject.text);

Y aquí el mensaje del alert(...) ya será ‘Clonning Objects’. Con esto ya podemos duplicar objetos… Pero, como no había quedado muy conforme con la solución seguí buscando, más por encontrar otro tipo de solución (no veo lógico que Javascript no tenga una forma nativa de clonar objetos) que por mejorar rendimiento. Y, aunque no encontré la forma nativa (creo que no la hay), sí encontré otra mucho más corta y más elegante:

function clone(o) {
return eval(uneval(o));
}

La función eval(...) coge un texto y lo evalúa como su fuese Javascript, de forma dinámica. Y, lógicamente, la función uneval(...) hace lo contrario: dado un código en Javascript —una clase, un array, etc.— lo convierte en el texto correspondiente, por lo que esta función lo que hace es convertir el objeto en texto y el texto generado otra vez en objeto, clonando así el objeto que se pasa como parámetro.

De estas dos formas, la segunda solución me parece más elegante —pocas cosas se consiguen en una sola línea de código—. El problema que puede existir es el rendimiento, ya que no he visto nada por ahí y yo tampoco he hecho pruebas, así que la decisión queda para cada uno. Yo he probado las dos y ambas funcionan sin problemas. Si alguien hace sus pruebas, que comente sus resultados.

La duda ofende

Error en Facebook con el navegador

Quizás los ingenieros de Facebook deberían revisar su algoritmo para reconocer con qué navegador estás viendo su página porque, que yo sepa, uso Firefox (la duda ofende) y no uso IE desde… vamos, que todavía tengo la versión 6 en mi máquina porque no quiero actualizar; para qué, si no lo uso. Además, este cacharro tampoco es que la aguantara.

Nuevo dominio (por fin)

Por fin he registrado Héctor me ha registrado el nuevo y definitivo dominio para este blog: beosman.org.

A partir de ahora tanto el blog como el feed estarán bajo esta URL por lo que ya pueden pasar a actualizar ustedes sus lectores RSS.

Supongo que quizás en un par de días habrá fallos de resolución de DNS hasta que no se extienda por todos los servidores pero el dominio está listo y, de momento, funcionando.

Las peleas de Xiao Xiao

No sé si os acordáis de los famosos vídeos en Flash de Xiao Xiao (mucho antes de que existiese YouTube) sobre peleas de kárate con monigotes de alambre:

Pantallazo de uno de los Flash de peleas de Xiao Xiao

La fecha en la que yo lo guardé es de 2001, pero seguro que estaba desde bastante antes. Pero todavía hoy impresiona ver la coreografía de los personajes monocolor de las peleas.