Ir directamente al contenido de esta página

codexexempla.org

Cómo mejorar la usabilidad de una tabla de datos por medio de JavaScript no obstrusivo (2) (y sigue sin ser zebra striping)

Tabla de contenidos

  1. Introducción
  2. Objetivos
  3. Solución
  4. Personalización
  5. Limitaciones
  6. Pruebas en navegadores

Aunque no es estrictamente necesario, recomiendo leer antes «Cómo mejorar la usabilidad de una tabla de datos por medio de JavaScript no obstrusivo», dado que algunos de los problemas a la hora de tratar con los elementos de una tabla son comunes.

Introducción

La inspiración viene de la mano de las cosas cotidianas, y si no pensemos en la magdalena de Proust. Hace poco, en el autobús, me encontré con que un hombre a mi lado comprobaba los datos de una tabla compuesta por decenas de celdas, con encabezados tanto para las filas como para las columnas, algo como esto:

Una tabla de ejemplo
Al Ca Sc Ti V Cr Mn Fe Co Ni Cu
001 0,25 1,22 1,05 0,72 1,23 0,09 0,34 1,23 1,03 1,12 0,01
002 1,02 1,99 0,26 1,14 1,02 1,91 0,96 0,72 1,17 0,96 0,12
003 1,71 0,61 1,12 1,09 1,17 0,99 0,54 1,61 0,36 0,22 1,59
004 0,09 0,03 1,98 0,25 1,10 0,17 1,50 1,78 1,02 0,77 0,90
005 1,11 1,09 1,11 0,64 0,26 1,58 1,26 0,32 1,70 1,33 0,71

Leerla, por supuesto, era un dolor de cabeza asegurado, por el esfuerzo necesario para cerciorarse de que se está leyendo la celda que corresponde a los dos encabezados que están relacionados. Como podría ocurrir que alguna vez me encontrase con una tabla semejante en una página, me puse a pensar en cómo facilitar su lectura.

Objetivos

Solución

El siguiente script modifica el estilo de las celdas de una tabla para identificar los encabezados relacionados con un td concreto, e identificar visualmente su relación:


 01  var posicion_celda = 0;
 02  var celda;
 03  var fila;
 04  var tabla;
 05  var celdas_fila;
 06  var filas_totales;
 07  function escuchar(){
 08  var celdas = document.getElementsByTagName('td');
 09      for (var i=1;i<celdas.length;i++){
 10          celdas[i].addEventListener('mouseover', resaltar_celdas, false);
 11          celdas[i].addEventListener('mouseout', restaurar_celdas, false);
 12      }
 13  }
 14  function resaltar_celdas(){
 15      celda = this;
 16      celda.className += ' celda_destacada';
 17      fila = this.parentNode;
 18      if (fila.parentNode=='[object HTMLTableElement]'){
 19          tabla = fila.parentNode;
 20      } else {
 21          tabla = fila.parentNode.parentNode;
 22      }
 23      celdas_fila = fila.getElementsByTagName('td');
 24      for (var i=0;i<celdas_fila.length;i++){
 25          if(celdas_fila[i]==celda){
 26              break;
 27          } else {
 28              posicion_celda++;
 29              celdas_fila[i].className += ' fila_resaltada';
 30          }
 31      }
 32      filas_totales = tabla.getElementsByTagName('tr');
 33      for (var k=1;k<filas_totales.length;k++){
 34          if(filas_totales[k]==fila){
 35              break;
 36          } else {
 37              filas_totales[k].getElementsByTagName('td')[posicion_celda].className += ' columna_resaltada';
 38          }
 39      }
 40      fila.getElementsByTagName('th')[0].className += ' encabezado_horizontal';
 41      tabla.getElementsByTagName('th')[posicion_celda].className += ' encabezado_vertical';
 42  }
 43  function restaurar_celdas(){
 44      celda.className -= ' fila_resaltada';
 45      fila.getElementsByTagName('th')[0].className -= ' encabezado_horizontal';
 46      tabla.getElementsByTagName('th')[posicion_celda].className -= ' encabezado_vertical';
 47      var celdas_totales = tabla.getElementsByTagName('td');
 48      for (var m=0;m<celdas_totales.length;m++){
 49          celdas_totales[m].className    -= ' fila_resaltada columna_resaltada';
 50      }
 51      posicion_celda = 0;
 52  }
 53  if (document.addEventListener){ window.addEventListener('load',escuchar,false); }
            

Tras declarar las variable que voy a necesitar, asigno escuchas a cada una de las celdas presentes en el documento para controlar los dos eventos de ratón que necesito controlar (líneas 10 y 11)1.

Cuando el usuario sitúa el puntero sobre una celda, se lanza la función resaltar_celdas. En ella primero asigno a esa misma celda el estilo que voy a emplear para resaltarla, por medio de la sintaxis celda.className +=, asegurándome así de que no elimino otras posibles declaraciones que puedan estar aplicándosele.

En las líneas 7 a 22 asigno a dos variables una referencia a la fila a la que pertenece la celda, y otra a la tabla —detectando antes si se ha empleado o no tbody—, que necesitaré un poco más tarde para saber la posición de la fila en cuestión. También incremento el valor de posicion_celda, una variable que luego me va a permitir elegir la celda que corresponde a la misma columna para las filas anteriores.

Entre la línea 23 y la 31, compruebo en el bucle cuál de las celdas de la lista de nodos que es fila es la celda actual; cuando la localizo, rompo el bucle, pero hasta entonces asigno a esas celdas un estilo diferente.

Seguidamente hago algo similar en las líneas 32 a 39: un bucle recorre las filas de la tabla hasta dar con la que tengo asignada a fila, y para cada fila anterior cambio el estilo de la celda que se encuentra en la misma posición que la resaltada.

Por último, en las líneas 40 y 41 asigno estilos también a los encabezados correspondientes, tanto horizontal como vertical.

La función restaurar_celdas es mucho más sencilla. Simplemente elimina los estilos adicionales, primero para la celda consultada (línea 44), después para los encabezados (líneas 45 y 46), y después para cualquier celda (líneas 47 a 50). Para terminar, restaura el valor de la variable posicion_celda, y el ciclo puede volver a empezar.

Ver un ejemplo de su funcionamiento.

Descargar el archivo .js.

Personalización

Una vez que se ha vinculado el script a la página que se desee, el aspecto de las celdas se puede especificar añadiendo unas pocas reglas a la hoja de estilo, como los siguientes selectores:

Limitaciones

He comprobado que este script funciona correctamente —sobre Windows— en:

Notas

  1. Es cierto que controlar el comportamiento de usuario de esta forma no cubre las necesidades de accesibilidad de los usuarios que no empleen un ratón, pero sucede que los eventos que serían independientes de dispositivo, como focus y blur, no se pueden aplicar a td, según la especificación sólo acepta los eventos comunes (inglés). Es este caso, lo único que puedo hacer en favor de la accesibilidad es hacer que el script no sea obstrusivo. Volver

Contacto

En virtud de la Ley Orgánica 15/1999 de Protección de Datos de Carácter Personal le informo de que los datos que proporcione no serán empleados para otro fin que el de responder a su mensaje. En especial, me comprometo a no cederlos a terceros ni a emplearlos para enviar información no solicitada.

Del blog de Digital Icon