Banner

Ultima revisión 12/01/2015

Crear tu propio Firebug con Javascript y jQuery

Una de las cosas que, habitualmente no pensamos es la potencia que nos puede brindar JavaScript y, aunque no siempre, lo fácil que puede llegar a ser hacer una buena herramienta para el web. Días atrás, he tenido que implementar un Depurador Web, vamos, algo así como un Firebug casero y dedicado y, la verdad, es que es más simple de lo que parece, sólo se necesita un poco de tiempo, paciencia y unos pocos métodos de JavaScript y jQuery.

Para este cometido, antes de nada, vamos a definir cuales son los elementos que se necesitan para gestionar todo lo que sucede en una página web. Evidentemente, en lo primero que pensamos, es los cambios de valor en los campos de texto pero hay muchas más cosas que, analizando un poco, podemos monitorizar:

Cambios de contenido en DOM

  • Cambios de atributo (por ejemplo id, class, style)
  • Cambios de valor. (eventos onChange, onSelect, onScroll, onInput)
  • Cambios de enfoque (eventos onFocus y onBlur)
  • Cambios de interacción con el ratón (eventos onClick, onDblClick)
  • Cambios de interacción con el teclado (eventos keyDown o keyPress)
  • Adición de elementos .
  • Eliminación de elementos

Los cambios de contenido en DOM, principalmente, se harán con los métodos de JavaScript MutationObserver y addEventListener.

Compatibilidad de MutationObserver con los navegadores

Este método, que es relativamente nuevo, proporciona a los desarrolladores una manera más de gestionar los cambios que se producen en el DOM. Puede tener prefijo asociado al método, es decir, que en vez de tener que llamarlo como MutationObserver, a lo mejor, se llama WebkitMutationObserver o MozMutationObserver, ... dependiendo del navegador, tiene multitud de opciones y, sobre la activación y configuración de este método, no es demasiado complicado aunque, si puede llegar a ser tedioso. Si deseáis conocer más sobre este tema, toda la información necesaria para poder utilizar esta característica la podéis extraer de las páginas W3C DOM Mutation-Observers y Observadores de mutación de Microsoft.

A continuación una pequeña tabla de la compatibilidad existente entre los diferentes navegadores y el método MutationObserver.

Navegador Soportado desde Uso Global Uso en España
IE 11+ 7.4% 5.77%
Firefox 31+ 10.16% 11.85%
Chrome 31+ 30.58% 31.93%
Safari 7+ 1.07% 1.43%
Opera 26+ 0.00% 0.10%
iOS Safari 7.1+ 7.90% 6.06%
Opera Mini No - -
Android Browser 4.4+ 3.14% 5.37%
Chrome for Android 39+ 9.51% 21.04%

Llamadas internas y externas a otros archivos o páginas

Con unas simples instrucciones y configuraciones de Ajax podemos monitorizar todas las llamadas a ficheros y webs internas y externas de nuestra página en curso. Para este caso utilizarecemos $.ajaxSetup, que nos da toda la potencia de una forma muy simple. Si no conocéis esta función o símplemente queréis más información se puede visitar las páginas de W3Schools o API jQuery.

jQuery.ajaxSetup({
    beforeSend: function(jqxhr, settings) {
        console.log('LLamando a');
    },
    complete: function(jqxhr, textStatus){
        console.log('Completada llamada a ');
    },
    success: function(data, textStatus, jqxhr) {
        console.log('Llamada satisfactoria a ');
    },
    error: function(jqxhr, textStatus, errorThrown) {
        console.log('La llamada aprodujo error...');
    }
});

Eventos de carga de las páginas

Con los eventos como ready, load y unload se puede controlar de manera muy sencilla a través de jQuery. Sobre este tema hay mucho en Internet así que no diré nada más.

$(document).ready(function(){ console.log("Página lista" });
$(document).load(function(){ console.log("Página cargada" });
$(document).unload(function(){ console.log("Página va a ser descargada" });

Control de errores de JavaScript

Otra cosa que muchas veces no pensamos es que, con unos cambios sencillos, podemos evitar los errores que ocurren en las páginas durante los procesos de carga e interacción con el usuario. Esto se puede controlar con el método onerror del objeto window.

window.onerror = null;
// Override del manejador de errores previo.
window.onerror = function (errorMsg, url, lineNumber) {
    console.log('Error: '+ errorMsg + ' en la línea '+  lineNumber + ' del archivo ' + url);
}

Como se puede ver, no hace falta mucho conocimiento para poder controlar prácticamente todo lo que sucede en JavaScript y, sí, muchas veces nos hacen falta unas herramientas como estas durante el proceso de desarrollo de un proyecto.

Bien, todo lo anterior está muy genial pero ... ¿ Existe alguna herramienta, plugin o librería que haga ya esto ?. Pues sí, se llama bugLow y es de la fábrica de IslaVisual.

bugLow: La librería de Islavisual lista para usar

Esta librería es una herramienta potente, fácil de usar y con multitud de opciones. Nos permite ver todo lo que pasa en nuestra web, puede funcionar como depurador, como sistema de Log's de JavaScript e incluso provee de la lógica necesaria para implementar las funcionalidades de Rehacer y Deshacer para objetos editables. A continuación os cuento un poco más en detalle sobre bugLow.

Características de bugLow

bugLow se caracteriza por tener:

Fácil instalación y configuración

Es muy fácil de instalar. Basta con incluir la librería en el HEAD de la página:

    <script src="js/buglow/buglow-min.js"></script>

La librería se puede descargar de Github bugLow y, para configurarla basta con una única instrucción:

    bugLow.init('console');    // Para depurar a través de consola
    bugLow.init('window');     // Para depurar en una ventana externa

Depuración selectiva

BugLow permite depurar selectivamente atributos, tags y eventos de manera independiente o combinada. La forma de especificar qué observar o no es a través de un array de valores que, para los ATRIBUTOS, sería:

    // Depurar todos
    bugLow.attributeFilter = [];
    // Depurar sólo cellspacing y cellspadding
    bugLow.attributeFilter = ['cellspacing', 'cellspadding'];
    // No depurar style, class, id y src... el resto si.
    bugLow.excludedAttributeFilter = ['style', 'class', 'id','src'];

Por defecto, attributeFilter esta definido a vacío y excludedAttributeFilter está definido a sólo el atributo style.

Para los TAGS, al igual que los atributos, se pueden especificar uno o varios, todos o ninguno:

    // Depurar todos
    bugLow.selectorFilter = [];
    // Depurar sólo cellspacing y cellspadding
    bugLow.selectorFilter = ['INPUT', 'SELECT', 'BUTTON'];
    // No depurar style, class, id y src... el resto si.
    bugLow.excludedSelectorFilter = ['DIV', 'SPAN', 'NAV','LEGEND'];

Por defecto, Las propiedades de selectorFilter y excludedSelectorFilter están definidos a vacíos.

Para los EVENTOS, se pueden especificar uno a uno los que se desean observar:

    // Depurar los ya predefinidos
    bugLow.eventFilter = [];
    // Depurar sólo el evento change.
    bugLow.eventFilter = ['change'];

La lista de eventos permitidos son, que ya los conocéis todos, click, mouseover, mouseout, mouseenter, mouseleave, keydown, keyup, keypress, change, focusin, focusout, focus y blur como los definidos en jQuery y JavaScript y, como añadidos, add y remove que, lo que hacen es monitorizar cuando los elementos añaden o eliminan uno o varios hijos.

Por defecto, si el parámetro eventFilter se deja vacío se observarán los eventos de change, click, focusin, focusout, keydown. En lo referente a eventos de teclado yo siempre recomiendo utilizar keydown porque permite controlar las teclas de Ctrl, Alt y Shift (mayúsculas).

Funcionalidad de Deshacer y Rehacer

bugLow provee de la lógica necesaria para gestionar de todas las modificaciones que se realizan sobre los campos de texto y desplegables incluso, aunque se recargue la página, por lo que es muy sencillo recuperar los valores anteriores. Sólo se requiere que el elemento tenga el atributo ID definido. Los métodos a utilizar son historyBack para realizar la funcionalidad de UNDO y historyForward para realizar la funcionalidad de REDO.

Un código de ejemplo de como realizar las acciones de UNDO o REDO sería:

    // Activar la funcionalidad UNDO / REDO
    bugLow.enableUndo = true;

    $('#idElement').keydown(function(e){
        if ( (e.which == 121 || e.which == 89) && e.ctrlKey ) {
            // Redo
            bugLow.historyForward(e.target.id);
            return false;

        } else if ( (e.which == 122 || e.which == 90) && e.ctrlKey ) {
            // Undo
            bugLow.historyBack(e.target.id);
            return false;
        }
    });

Histórico Exportable

Es fácilmente exportable a fichero ya que se puede guardar como una página web más, desde la ventana externa o, a través de la función getHistory que devuelve la historia en formato cadena (String). Para utilizar esta característica sólo se debe activar y llamar a la función de importación.

    // Activar el histórico
    bugLow.enableHistory = true;

    // ....
    // ... Aciones ...
    // ....

    // Recuperar el histórico hasta el momento en un string
    bugLow.getHistory();

Descripciones con selectores de CSS

Permite ver, de forma fácil, los elementos que han sido modificados a través de selectores absolutos. Luego estos selectores se puede utilizar para definir nuevas modificaciones en las hojas de estilo CSS. Por ejemplo:

    BODY > HEADER > NAV.navbar > DIV.container > DIV.navbar-header > A.navbar-brand > #logo_menu.

Control de Ajax

Permite tener un control total sobre todas las llamadas a URL internas y externas de jQuery y Ajax. Controla los eventos de beforeSend, success, complete y error.

Control sobre el Teclado

Se puede saber qué combinación de teclas se ha pulsado en todo momento y en qué elemento incluyendo los códigos de tecla. Con esta información luego podemos hacer filtrados como, por ejemplo, INPUTS que permitan únicamente números. Por ejemplo

    Keyboard event received into BODY > DIV.wrapper > SECTION.articles > DIV.container > ARTICLE > #inputText element. Keys Combination: "Ctrl + X". Keys Combination Code: "17 + 88".

Parámetros por URL

BugLow puede configurarse a través de los parámetros de la URL. A continuación se muestran el listado de parámetros configurables a través de la URL. Se pueden utilizar tanto las abreviaturas como los nombres largos.

Parámetro abreviado Equivale a
afattributeFilter
eafexcludedAttributeFilter
sfselectorFilter
esfexcludedSelectorFilter
efeventFilter
henableHistory
uenableUndo
ttarget ('console' o 'window')

Mensajes personalizables

Se puede definir mensajes personalizados para cada tipo de evento o mutación.

    messages:{
        ajaxBeforeSend:'Processing request. Method: <method>. Type: <type>. CrossDomain: <crossDomain>.  File: <url>. Content Type: <contentType>',
        ajaxComplete:'The Ajax processing request FINISHED for the <url> file.',
        ajaxSuccess:'The Ajax request was completed SUCCESSFULLY for the <url> file.',
        ajaxError:'An error occurred into Ajax processing request into <url> file.',
        beforeUnloadPage:'Page request unload',
        unloadPage:'Unloaded page',
        errorPage:'An error occurred into file',
        parsedPage:'Page loaded and parsed.',
        pageChangedStatus:'Page changed status:',
        valueChanged: 'The <selector> changed the value property to <value>.',
        getsFocus: '<selector> gets focus.',
        losesFocus: '<selector> loses focus.',
        click: 'User clicks into <selector>.',
        attributeMutation: 'The <attributeName> attribute has mutated from "<oldValue>" to "<value>" into <selector> element.',
        addedChildren: 'Added children into <selector> element. Total children: <totalChildren>',
        removedChildren: 'Removed children into <selector> element. Total children: <totalChildren>',
        mouseOver: 'The mouse pointer is over the <selector> element.',
        mouseOut: 'The mouse pointer leaves the <selector> element.',
        keyPress: 'Keyboard event received into <selector> element. Keys Combination: "<keys>". Keys Combination Code: "<keysCode>".',
        separator: '<div style="border: 1px solid #333; border-width: 0px 0px 1px 0px; height:5px; width:100%;margin-bottom: 5px;"> </div>'
    }

Colores personalizables

Se pueden definir distintos colores para cads evento o mutación.

    colors: {
        added:"#709050",                // Para elementos añadidos en el DOM
        attributeChanged: '#ff00ff',    // Para cambios en attributos en el DOM
        background:"#000000",           // Fondo de la ventana de BUGLOW
        blur:"#907080",                 // Para eventos Blur
        focus:"#9070a0",                // Para eventos Focus
        click:"#909090",                // Para eventos Click
        mouseOver:"#a07090",            // Para eventos Mouse Over
        mouseOut:"#807090",             // Para eventos Mouse Out
        keyPress:"#80a090",             // Para eventos Keypress
        error: '#a02020',               // Para los errores detectados
        headerForeground:"#ffffff",     // Texto de la Cabecera
        headerBackground:"#333",        // Fondo de la Cabecera
        normal:"#606060",               // Para cambios estándar y no registrados
        proccessing:"#8AC007",          // Para Ajax en modo Procesando
        readyState:"#8AC007",           // Para cambios de estado de los Ajax
        removed: "#a01010",             // Para elementos eliminados en el DOM
        sending:"#8AC007",              // Para Ajax en modo Enviando
        updated:"#80a0e0",              // Para Ajax en modo Actualizando
        valueChanged:"#FE2466"          // Para cambios en los atributos value
    }

Ejemplos de cambios

Pulsa Ctrl + Z para hacer UNDO, Ctrl + Y para hacer REDO