Delirios de un Informático

Funciones personalizadas para Less mediante Grunt

Less dispone de muchas funciones nativas, pero hay ocasiones en las que resultaría útil disponer de funciones personalizadas porque los mixins tampoco son suficientes. Por ejemplo, puede ser útil comprobar si existe un archivo, leer su contenido o ejecutar una herramienta externa para obtener los valores.

Para estos casos, es posible añadir nuevas funciones a Less mediante Grunt y el plugin grunt-contrib-less mediante la opción customFunctions, con lo que tendremos toda la potencia de Node.js a nuestra disposición para realizar todo que se nos ocurra.

Este sería el contenido de un Gruntfile.js de ejemplo:

module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-less');

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        less: {
            options: {
                customFunctions: require('./functions.js'),
                sourceMap: false
            },
            build: {
                src: 'test.less',
                dest: 'test.css'
            }
        }
    });

    grunt.registerTask('default', ['less']);
};

Como se puede ver, utilizo un require('./functions.js') para almacenar en un archivo todas las funciones, que deben exportarse del siguiente modo:

exports.test = function(less, arg1, arg2) {
    // código personalizado
}

Cada función se exporta con un nombre que será el utilizado en Less:

body {
  background-color: test('test.jpg', #FFFFFF);
}

Hay que tener en cuenta los siguientes aspectos:

  • El primer argumento recibido por la función es una instancia del compilador Less
  • El resto de argumentos son los que se especifiquen en Less
  • Cada argumento es un objeto con las siguientes propiedades (entre otras):
    • value: valor especificado en Less
    • quote: entrecomillado usado para convertir el valor
    • escaped: indica si se aplicarán caracteres de escape en el valor
  • Cualquiera de las propiedades puede modificarse para que el compilador las utilice
  • El entrecomillado será el especificado en Less: ‘, ” o ninguno si se usa un color o cualquier otro valor CSS
  • El valor de retorno de la función puede ser un objeto como el recibido como argumento o una cadena que se mostrará tal cual

El único problema que no he logrado solventar es poder acceder a las variables definidas en el punto en el que se llama a la función. Sería muy útil poder acceder a las variables, añadirlas y modificarlas, pero por lo que he podido comprobar la instancia de Less recibida por la función no da acceso a ellas.

elRTE: WYSIWYG basado en jQuery UI

elRTE es un nuevo editor WYSIWYG para la web basado en jQuery UI. Es muy ligero principalmente porque no tener que cargar su propio framework (como hace el pesadísimo TinyMCE) y consta de un único archivo JS, un par de CSS y menos de 100kb de imágenes. Es 100% Open Source y muy fácil de instalar.

Cómo evitar fbc_channel=1 con Facebook Fan/Like Box

Muchos usuarios están teniendo problemas con los módulos Like Box debido a que aparecen en las estadísticas múltiples llamadas a URLs del tipo midominio.com/?fb_channel=1&.... En muchos casos provoca que la página se refresque cada pocos segundos siendo de lo más irritante.

El problema radica en que no se está especificando la ruta del archivo para la comunicación interdominios xd_receiver.htm e intenta por defecto realizar la llamada contra la raiz del sitio. Para solucionar el problema, basta añadir una llamada a FB.init() antes del código XFBML o del IFRAME:

<script type="text/javascript">FB.init('CLAVE_API', '/ruta/a/xd_receiver.htm');</script>
<fb:like-box profile_id="ID_PAGINA" stream="false" header="false"></fb:like-box>

Facebook proporciona información sobre la Cross Domain Communication en esta página.

Redimensionar la ventana de Firefox sin extensiones

Para los que usamos versiones de desarrollo de Mozilla Firefox (actualmente trabajo con la 4.0pre3 para 64bits) es una lata tener un montón de extensiones que hay que modificar para poder instalarlas. Únicamente uso Firebug (1.6X.0a18 concretamente) pero tengo la necesidad de probar diferentes resoluciones en las páginas que desarrollo y lo ideal para mí es no depender en absoluto de extensiones. Por eso este pequeño tip: basta añadir favoritos con el siguiente código:

javascript:window.resizeTo(800x600);void(0);
javascript:window.resizeTo(1024,768);void(0);
javascript:window.resizeTo(1280,800);void(0);

Rápido, sencillo y sin sobrecargar el navegador con extensiones :).

Google Translate Element con selector personalizado

Google pone a disposición de los programadores esta utilidad que permite realizar de un modo muy sencillo traducciones de cualquier página web. Si se implementa tal cual se proporciona el código, se añadirá un selector de idiomas y un texto tipo Con la tecnología de Google y puede desentonar con el diseño o simplemente no gustar nada (como es mi caso). Por eso, he trasteado un poco para poder crear mi propio selector de idiomas.

Primero ha de añadirse la función un poco mejorada indicando el idioma base y la lista de posibles idiomas a los que puede traducirse:

function googleTranslateElementInit(force) {
	base = 'gl';
	if(force == true) {
		new google.translate.TranslateElement({
			pageLanguage: base,
			includedLanguages: 'ca,en,es,gl'
		}, 'google_translate_element');
	} else if(force == undefined) {
		if(window.location.href.indexOf('#googtrans/') != -1) {
			googleTranslateElementInit(true);
		}
	} else {
		url = window.location.href.replace(/\#googtrans\/.+$/, '');
		window.location.href = url + '#googtrans/' + base + '/' + force;
		window.location.reload(true);
	}
}

Luego, se necesita incluir normalmente el archivo JavaScript que permite la traducción:

<script type="text/javascript" charset="utf-8" src="http://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

Una vez incluido todo el JavaScript basta con llamar a la función con el idioma que se desee. Por ejemplo: googleTranslateElementInit('en');. La página se recargará y traducirá al idioma elegido, pudiendo pulsar el cualquiera de los otros idiomas….