Qué elemento HTML hemos de usar para presentar el código fuente

botones contenedor código resaltado He actualizado el contenedor de código resaltado para mostrar una barra de botones con algunas utilidades como numerar líneas de código o imprimir código. A la hora de acometer esto me he encontrado con algunos problemas relacionados con el manejo de los espacios blancos o white space. Los espacios blancos son el espacio normal, la tabulación ASCII 9 y el salto de línea ASCII 13, éste último también es ASCII 10 + 13 en Windows. El código fuente se escribe con un sangrado de las líneas de texto (también escrito como indentado, un anglicismo de la palabra indent que se traduce como "sangrar líneas de texto"). Yo no uso la tabulación pues no se presenta igual en todos los editores. Configuro mi editor para que use 4 espacios normales en una tabulación. Pero a la hora de transferir un texto de código a un elemento apropiado de HTML podemos tener algunos problemas con los espacios blancos que intentaré exponer y resolver en este tema.

Veámos algunos ejemplos probados en Chrome 22.0, Firefox 16.0, Opera 12.02, Safari 5.1.7 e Internet Explorer 8. Partimos de la base de que necesitamos incorporar código fuente resaltado, es decir, con formatos de color. En primer lugar se nos ocurre meter el código fuente en un elemento <div> con estilo white-space: pre. El navegador respetará todos los espacios blancos tal como fueron escritos en el código del siguiente ejemplo (utilizaré texto de ejemplo en lugar de una representación de código pues lo que interesa son los espacios blancos):

Ejemplo:

Una línea con un salto Y otra que empieza con 4 espacios con una línea muy larga que supera el ancho mínimo de esta página.

El código se presenta con fuente monoespaciada y hay una palabra resaltada con color rojo. La segunda frase es bastante larga con objeto de que supere el contenedor. El código de lo anterior es el siguiente (he reducido la frase larga para no ocupar mucho):

<div style="white-space: pre;
border: green solid 1px;
font-family: monospace;
overflow: auto;">Una línea con un salto
    Y <span style="color: red">otra</span> que empieza con 4 espacios ... </div>

Con un <div> es necesario poner el texto sin dejar espacios en el interior, es decir, exactamente después del tag de apertura y antes del de cierre. En otro caso esos espacios también son representados. Con overflow: auto se activará la barra de desplazamiento (scroll) horizontal cuando el texto no quepa en el ancho disponible. Este efecto de no cortar las líneas más largas que el ancho del contenedor es el adecuado para ver código fuente. Por lo tanto parece ser que un <div> con white-space: pre es adecuado para presentar código fuente resaltado. Pero unas de las cosas que podemos hacer con el código fuente es copiarlo para pegarlo en alguna aplicación editora externa. Por ejemplo, puede pegarlo en un editor de texto de su ordenador o en este elemento <textarea>:

Ejemplo:

Los navegadores consultados a excepción de Firefox reciben el texto en el <textarea> correctamente, respetando los saltos de línea. Firefox reduce más de un espacio a uno sólo y cambia el salto de línea por un espacio. Como la acción de copiar código es importante intentaremos usar un elemento <pre> en lugar del <div> con white-space: pre:

Ejemplo:

Una línea con un salto
    Y otra que empieza con 4 espacios con una línea muy larga que supera el ancho mínimo de esta página.

El código es el siguiente:

<pre style="border: green solid 1px;
overflow: auto;">
Una línea con un salto
    Y <span style="color: red">otra</span> que empieza con 4 espacios ... </pre>
    

El resultado en pantalla es exactamente igual que el anterior. Aunque hay algunos detalles que comentar. Con <pre> no necesitamos que el texto empiece inmediatamente tras el tag de apertura, pues todos los espacios blancos que hayan al inicio serán ignorados. Aunque se tienen en cuenta los espacios antes del tag de cierre. Por eso el tag </pre> va inmediatamente después de finalizar el texto. Ahora podemos copiar y pegar el texto en el <textarea> con Firefox pegándose con todos los espacios blancos. Pero ¿qué pasa si sustituímos los saltos de línea por elementos <br />?.

Ejemplo:

Una línea con un salto
Y otra que empieza con 4 espacios con una línea muy larga que supera el ancho mínimo de esta página.

con este código:

<pre style="border: green solid 1px;
overflow: auto;">
Una línea con un salto<br />    Y <span style="color: red">otra</span> que empieza con 4 espacios ... </pre>

Vea que ahora este código no tiene ningún salto de línea de texto, sino un <br />. La presentación en el <pre> de los navegadores consultados se conserva como el ejemplo anterior. Copiar y pegar el texto en el <textarea> anterior (o en un editor de texto externo) funciona en los navegadores consultados a excepción de IE8. Todos convierten el salto <br /> en un salto de texto (\n o \rn), menos IE8 que lo ignora.

¿Y qué razón hay para usar <br /> en lugar del salto de texto?. En mi contenedor caben las dos opciones. Por un lado con código resaltado y comprimido cuando hacemos la descompresión convertirá todos los saltos \n en <br />. Al descomprimir hacemos uso de expresiones regulares y así evitamos modificadores multilínea que dan algunos problemas, aparte de no tener que estar buscando \n o \r\n según sea la plataforma. Pero el contenedor también puede recibir estos saltos de texto, aunque para realizar algunas operaciones como numerar líneas es más cómodo cambiarlos por saltos HTML. En definitiva, el salto HTML es entendido por todos los navegadores de la misma forma y causa menos problemas.

Por lo tanto el contenedor de código resaltado debe ser capaz de manejar saltos de texto y HTML. Como la acción de copiar y pegar es importante cuando hay código fuente, mi contenedor incluye el botón   para presentar texto plano (con saltos de texto, no de HTML). Al actuar se presenta un elemento <textarea> con las mismas medidas y posición que el elemento <pre> y situado en una capa superior. Ahí podemos copiar el texto con cualquier navegador (de los probados) y pegarlo en un editor de texto respetándose todos los espacios blancos. Otra ventaja del <textarea> es que incorpora el menú para seleccionar todo y copiar, con lo que facilitamos esta tarea al usuario.

En un apartado en el tema siguiente se expone el JavaScript que convierte el código resaltado en texto plano, por si le interesa ver más sobre esto. Pero antes de pasar al JavaScript conviene ver la estructura HTML y CSS del nuevo contenedor de código resaltado.

Estructura del contenedor de código resaltado

El contenedor de código resaltado tiene actualmente (estos códigos son los que actualmente estoy usando, pero puede que los modifique en el futuro. Para ver la versión más actualizada puede usar el botón de Código de esta página, en la barra de botones de la cabecera) la siguiente estructura HTML:

<div class="codigo-resalte"><ul>
    <li title="Numerar líneas" data-sprite-src="/res/img/blanco.gif"><span
        onclick="numerarResalte(event)">12</span></li>
    <li title="Texto plano para copiar"
        data-sprite-src="/res/img/copiar16.png"
        onclick="textoPlanoResalte(event)">&nbsp;</li>
    <li title="Vista previa"
        data-sprite-src="/res/img/vistaprevia16.png"
        onclick="imprimirResalte(event, true)">&nbsp;</li>
    <li title="Imprimir" data-sprite-src="/res/img/impresora16.png"
        onclick="imprimirResalte(event, false)">&nbsp;</li>
    <li title="Herramienta para resaltar código fuente"
        data-sprite-src="/res/img/wx_verde16.png"><a
        href="resaltador/"><img class="icono"
        src="/res/img/blanco.gif" width="16" height="16" alt="icono" /></a></li>
</ul><pre class="a">...AQUÍ VA EL CÓDIGO RESALTADO...</pre><textarea wrap="off" style="display: none"></textarea></div>

Tenemos un <div> externo que recoge una lista <ul> para disponer los botones. Luego está el <pre> donde metemos el código resaltado y finalmente el <textarea> para exponer el texto plano. Para las imágenes de los botones uso la técnica de Sprites CSS, insertando directamente el sprite dentro del elemento de lista <li>. Un evento onclick ejecuta la acción. El <pre> y <textarea> reciben el código fuente resaltado y el texto plano respectivamente, tal como comentamos en el apartado anterior. El <pre> tiene clase class="a" que es el estilo de fondo del resaltador de código. El <textarea> tiene el atributo wrap="off" que desactiva el salto de línea automático que es el comportamiento por defecto de esos elementos.

El estilo actual del CSS que maneja este HTML está en el archivo resaltador.css. Contiene las clases desde la "a" hasta la "p" para manejar el resaltado de código. Luego tiene el estilo para el contenedor de código. No hay mucho que decir de este CSS, si acaso que el <div> exterior tiene posicionamiento relativo (position: relative) porque al <textarea> le daremos con JavaScript posicionamiento absoluto (position: absolute) para poder ubicarlo en la misma posición que el <pre>. También lo ponemos en una capa superior con z-index: 1.


En el tema siguiente veremos todo el JavaScript de la acciones de los botones.