Ver el código fuente resaltado de las páginas web

Menú ver código fuente

En este sitio he venido ofreciendo el código resaltado de los documentos mediante el botón Código de la barra de menú superior. Las páginas de este sitio están minimizadas o minificadas, por lo que el usuario no puede leer fácilmente el código usando la funcionalidad de los navegadores Ver código fuente. Además el código que vemos en el navegador no es el verdadero código fuente en los casos en que el servidor modifica contenidos con PHP. Así cuando publico un nuevo artículo subo también el código resaltado de la página. Esto lo he venido haciendo con la herramienta resaltador (con PHP) para usar en un marco de herramientas en localhost.

Había estado revisando esa herramienta resaltadora de código y ahora quería agregarle nuevas mejoras. Tras algunos intentos comprobé que el diseño inicial era algo deficiente y me planteé empezarla otra vez desde cero con una perspectiva diferente: hacerla en JavaScript y luego traducirla a PHP para incorporarla a mi marco de herramientas localhost.

La razón de hacerla en JavaScript es porque podía poner esa versión on-line (Resaltador código con JavaScript) y así ofrecer un nuevo servicio a los usuarios de este sitio. No está de más recordar que no ejecuto las herramientas con PHP que tengo en locahost en este servidor en producción debido a los recursos que consumen. Pero las herramientas en JavaScript, que tienen limitaciones respecto a las de PHP, al menos no consumen recursos del servidor sino del navegador.

Este nuevo resaltador, al igual que el anterior, usa expresiones regulares para diferenciar las partes del código. Y se tiene que entender que esto no es un parseador de código. Es imposible tener la seguridad de realizar un correcto resaltado sin errores al 100% usando sólo expresiones regulares. Pero parsear código sólo para su resaltado es una tarea de mayor complejidad. Por lo tanto y a pesar de realizar test de ejemplos en diversas situaciones de código, podrán aún quedar casos de resaltados erróneos. Mi objetivo en todo caso ha sido reducir esos casos de error al mínimo.

En esta página explicaré como usar los módulos resaltador-codigo.js y resaltador.js. Estos enlaces presentan el código fuente original de esos módulos que actualmente estoy usando en este sitio. Pero esos JS, que están aquí minimizados (o minificados) contienen dependencias externas a otros módulos como general.js. Si quiere ver los recursos integrando todas las dependencias o descargarlos use la utilidad de ejemplos integrados al inicio de este artículo.

Usando código resaltado por la herramienta

Sin necesidad de usar los módulos resaltador-codigo.js o resaltador.js, podemos insertar el HTML del código resaltado tal como sale en la herramienta resaltadora tras pulsar el botón de Exportar resalte y meterlo en un elemento <pre class="a"> como el siguiente ejemplo:

Ejemplo: Resaltado en un PRE class="a"

<div onclick="var a=123; alert(a);">
    <b id="abc">ABCDE</b>
</div>
<script>
    var a = "abc";
    var b = 12.345;
    var c = /[a-z]*/g;
    var d = function(){};
</script>
<style>
    div.miclase {
        color: red;
        z-index: 5;
    }
</style>

Sólo necesitamos copiar la hoja de estilo de la pestaña Opciones e incluirla en un elemento STYLE en la cabecera de la página.

<style id="css-resaltador-codigo">
    .a {color: black; font-weight: normal; font-style: normal}
    .b {color: red; font-weight: bold; font-style: normal}
    .c {color: purple; font-weight: bold; font-style: normal}
    .d {color: orangered; font-weight: normal; font-style: normal}
    .e {color: blue; font-weight: normal; font-style: normal}
    .f {color: gray; font-weight: normal; font-style: normal}
    .g {color: steelblue; font-weight: normal; font-style: italic}
    .h {color: blue; font-weight: bold; font-style: normal}
    .i {color: deeppink; font-weight: bold; font-style: normal}
    .j {color: red; font-weight: normal; font-style: normal}
    .k {color: mediumorchid; font-weight: normal; font-style: normal}
    .l {color: maroon; font-weight: normal; font-style: normal}
    .m {color: darkgreen; font-weight: normal; font-style: normal}
    .n {color: blue; font-weight: normal; font-style: normal}
    .o {color: teal; font-weight: normal; font-style: italic}
    .p {color: navy; font-weight: normal; font-style: normal}
    .q {color: olive; font-weight: normal; font-style: normal}
    .r {color: peru; font-weight: normal; font-style: normal}
    .s {color: blueviolet; font-weight: normal; font-style: normal}
    .z {color: black; font-weight: normal; font-style: normal}
</style>

El ID del elemento STYLE no es necesario para esta acción, aunque si lo será cuando usemos el módulo resaltador-codigo.js como veremos a continuación.

Usando los módulos resaltador-codigo.js y resaltador.js

Al final del BODY de esta página encontrará el siguiente código, poniendo por ahora sólo lo necesario para entender el proceso:

<script>
    var wxR, wxRC;
    ...
    Wextensible.iniciarPagina = function() {
        ...
        wxR = Wextensible.resaltador;
        wxRC = Wextensible.resaltadorCodigo;
        wxRC.iniciar();
        ...
        //Uso de resaltador-codigo.js ---------------------------------
        //Resalta todos los códigos en elementos con class="a" y 
        //data-tipo="html|css|js|php"
        wxRC.resaltarListaElementos(document.getElementsByClassName("a"));
        ...
    };
        window.onload = function() {
            if (Wextensible.generalJs){
                Wextensible.iniciarPagina();
            } else {
                var elemento = document.createElement("script");
                if (elemento.addEventListener){
                    elemento.addEventListener("load", Wextensible.iniciarPagina);
                } else if (elemento.readyState == "uninitialized") {
                    elemento.attachEvent("onreadystatechange", function(){
                        if (elemento.readyState == "loaded") Wextensible.iniciarPagina();
                    });
                }
                elemento.async = true;
                elemento.src = "/res/inc/general-old.js";
                var head = document.getElementsByTagName("head")[0];
                if (head) head.appendChild(elemento);
            }
        };//fin onload
</script>
<script src="/res/inc/resaltador-codigo.js" async></script>
<script src="/res/inc/resaltador.js" async></script>

Los dos módulos JS están construidos dentro del espacio de nombres Wextensible. Declaramos las variables wxR y wxRC para referenciar al resaltador de código que exponemos en el siguiente apartado y al resaltador que permite descomprimir código que exponemos en el último apartado.

A la carga de la página referenciamos ambos módulos y luego es necesario iniciar el resaltador de código. A partir de ahí podemos resaltar todos los elementos que contengan la clase "a" del documento, como veremos en un siguiente apartado.

El estilo del resaltado se incorpora automáticamente con el script resaltador-codigo.js si no existiera previamente. En el HEAD de este documento podrá encontrar el elemento STYLE generado por ese módulo (no existía previamente), el mismo que expusimos en el apartado anterior. Vea que tiene un id="css-resaltador-codigo" que nos sirve para comprobar su existencia.

Estos estilos se definen en resaltador-codigo.js y también ahí se relacionan estos estilos con las diferentes partes del código a resaltar:

//Tipos de clases que se adjudican a las partes resaltadas del documento
tiposClases: {
    pre: "a",           //Contenedor de código block PRE
    code: "a",          //Contenedor de código inline CODE
    //HTML
    tag: "c",           //Tag HTML
    tagcar: "k",        //Entidad caracter
    tagphp:  "b",       //Tag PHP
    tagip: "f",         //Tag instrucción procesamiento
    tagdoctype: "r",    //Tag DOCTYPE
    commenthtml:"o",    //Comentario HTML
    cdata:"q",          //Seccion CDATA
    attrname: "d",      //Nombre atributo HTML
    attrvalue: "e",     //Valor atributo HTML
    ...

Por ejemplo, un TAG de HTML se le asigna la clase "c" con el estilo color: purple; font-weight: bold. Por lo tanto podemos personalizar ese script para que se adapte a las necesidades de cada uno.

Ejemplos de resaltes: uso de resaltador-codigo.js

Los elementos CODE y PRE en esta página tiene estilo declarado en el archivo base.css que define el estilo para todo el sitio. Definen color marrón, fuente monoespaciada, tamaño de fuente, borde punteado para el PRE y otras cosas para adaptar la estructura de texto similar a código en cualquier página de este sitio. Pero no contemplan ningún estilo de resalte de contenidos:

code {
    font-size: 1em;
    font-family: "Lucida Console", "Courier New", monospace;
    color: maroon;
    word-wrap: break-word;
}
pre {
    border: maroon dotted 1px;
    width: 100%;
    overflow: auto;
    font-size: 14px;
    font-family: "Courier New", monospace;
    color: maroon;
}

Este estilo que denominaremos estilo base se sobrescribe o amplia con el estilo que insertará el resaltador, donde sólo manejamos estilo de color, fuente negrita y/o itálica. A continuación se exponen una serie de ejemplos usando contenedores CODE y PRE dotados de class="a" que agregarán contenido resaltado usando la instrucción

wxRC.resaltarListaElementos(document.getElementsByClassName("a"));

declarada en el window.onload de esta página.

Este código <b id="abc"> está dentro de un elemento CODE sólo con estilo base (le he agregado un borde para diferenciarlo mejor). Contiene texto donde escapamos lo caracteres "&", "<" y ">" por sus escapes HTML "&amp;", "&lt;" y "&gt;" respectivamente. Si le agregamos class="a" data-tipo="html" al siguiente CODE con igual contenido queda resaltado como sigue: <b id="abc">.

A continuación hay un elemento PRE también sólo con estilo base y con código escapado para "&amp;, &lt;, &gt;". Esta es la forma más simple para presentar código:

Ejemplo: Código sin resaltar en un PRE

<div onclick="var a=123; alert(a);">
    <b id="abc">ABCDE</b>
</div>
<script>
    var a = "abc";
    var b = 12.345;
    var c = /[a-z]*/g;
    var d = function(){};
</script>
<style>
    div.miclase {
        color: red;
        z-index: 5;
    }
</style>

A otro PRE con el mismo contenido agregándole class="a" data-tipo="html" quedará resaltado así:

Ejemplo: Resaltado en un PRE class="a"

<div onclick="var a=123; alert(a);" >
    <b id="abc">ABCDE</b>
</div>
<script>
    var a = "abc";
    var b = 12.345;
    var c = /[a-z]*/g;
    var d = function(){};
</script>
<style>
    div.miclase {
        color: red;
        z-index: 5;
    }
</style>

Observe como el código dentro de SCRIPT y STYLE se resalta con el tipo adecuado JS y CSS respectivamente. Además el código JavaScript dentro del atributo ONCLICK tambien queda resaltado con el tipo JS. Si no queremos resaltar este código de eventos podemos poner la variable wxRC.resaltarEventos a false en el módulo resaltador-codigo.js, donde también podemos modificar la configuración de resalte como veremos en un apartado más abajo.

Ahora tenemos un DIV con estilo para el contenedor (borde, relleno y color de fondo) especificado en su atributo STYLE (bloque con borde azul y fondo beige). El contenido es código CSS escapado:

Ejemplo: Código sin resaltar en un DIV

<style> .menuwx-desp > ul li > form input[type="text"] { background-color: white; color: navy; margin-right: 0.2em; padding: <?php echo $long + 0.35; ?>em; } </style>

El DIV resume todos los espacios blancos en un único espacio simple y por tanto no es adecuado para presentar código. Pero si le agregamos class="a" data-tipo="html" queda así:

Ejemplo: Código resaltado en un DIV class="a"

<style> .menuwx-desp > ul li > form input[type="text"] { background-color: white; color: navy; margin-right: 0.2em; padding: <?php echo $long + 0.35; ?>em; } </style>

Observe el contenedor PRE con borde punteado que se ha insertado dentro del DIV reemplazando el contenido previo. El atributo data-tipo declara que tipo de código se resalta. Sus valores pueden ser html, css, js y php. Este atributo data-tipo es obligatorio cuando usemos la función wxRC.resaltarListaElementos(listaElementos). Si el elemento donde vamos a resaltar es distinto de PRE o CODE, el resaltador incluirá todo el resalte en un PRE o CODE según que el contenedor de referencia sea de bloque o línea.

Observe como podemos incluir nodos PHP dentro del tipo html. Si quisiéramos resaltar sólo código PHP "puro" (sin nodos PHP) pasaríamos data-tipo="php" como en este ejemplo:

Ejemplo: Código resaltado PHP

//Código PHP puro sin nodos <?php ... ?> $mi_var = "abc"; $otra_var = 1234; function mi_funcion($arg){ global $mi_var; return $arg."xyz".$mi_var; }

En caso de tener el código incluido en un elemento SPAN que es de tipo inline como var x = "abc"; se resaltaría así var x = "abc";. En este caso le hemos pasado class="a" data-tipo="js".

Resaltando código desde una variable JavaScript

El módulo resaltador-codigo.js tiene también la función resaltar() que nos devuelve el código resaltado desde un argumento con el código que le pasamos. En esta página hay este código HTML y el SCRIPT de final de página:

<pre id="prevar"></pre>
...
<script>
    var wxG, wxR, wxRC;
    //Nota: cuando expresamos en un string código con nodos PHP, hemos 
    //de separar tags PHP puesto que al ponerlo en esta página que se 
    //sirve como PHP leerá ese nodo PHP.
    var codigo = '<div class="xyz">\n\t<' + '?php echo "abc"; ?' +
                 '>\n</div>';
    ...
    Wextensible.iniciarPagina = function() {
        ...
        wxRC = Wextensible.resaltadorCodigo;
        ...
        //Resalta código desde una variable y lo inserta en un elemento
        var preVar = document.getElementById("prevar");
        prevar.innerHTML = wxRC.resaltar(codigo, "html", "", "");
        ...
    };
        window.onload = function() {
            if (Wextensible.generalJs){
                Wextensible.iniciarPagina();
            } else {
                var elemento = document.createElement("script");
                if (elemento.addEventListener){
                    elemento.addEventListener("load", Wextensible.iniciarPagina);
                } else if (elemento.readyState == "uninitialized") {
                    elemento.attachEvent("onreadystatechange", function(){
                        if (elemento.readyState == "loaded") Wextensible.iniciarPagina();
                    });
                }
                elemento.async = true;
                elemento.src = "/res/inc/general-old.js";
                var head = document.getElementsByTagName("head")[0];
                if (head) head.appendChild(elemento);
            }
        };//fin onload
</script>

Hay un elemento PRE con id="prevar" sin ningún contenido. En el script del pie de página hay una variable codigo que porta el código a resaltar. En este caso no tiene escapes HTML &amp;, &lt;, &gt;. Ejecutamos wxRC.resaltar(codigo, "html", "", "") pasando el código, el tipo "html", una cadena vacía para que no inserte ningún contenedor y finalmente otra cadena vacía que le dice que no hay ningún caracter escapado. Finalmente el resultado se insertó como sigue:

Ejemplo: Código resaltado PHP

Estamos en este caso pasando el código dentro de una variable JavaScript, representando los saltos de línea con "\n" y los tabuladores con "\t". Además en los nodos PHP <?php ... ?> deben escaparse los caracteres "?" con el escape "\x3f" para JavaScript, porque está página es tratada como PHP por mi servidor y al encontrar ese nodo lo ejecutaría.

Resaltando con configuraciones

Usando JavaScript con el módulo resaltador-codigo.js podemos adaptar la configuración del resalte. En el script al final de esta página encontrará lo siguiente:

//Primer ejemplo con la configuración por defecto 
var code = wxRC.resaltar('<div id="abc">config 1</div> ' +
    '<' + '!-- CONFIG 1 --' + '>', "html", "", "");
document.getElementById("config1").innerHTML = code;
//Guardamos esta configuración
var configSalvado = wxRC.exportarConfig();
    

Al igual que lo explicado en el apartado anterior, resaltamos un trozo de código HTML y lo metemos en un elemento <pre id="config1"> vacío que está a continuación, generándose el resalte en su interior.

Ejemplo: Salvando configuración de resalte

Antes de seguir salvamos o guardamos la configuración existente con wxRC.exportarConfig() porque vamos a modificar la configuración de resalte:

//La modificamos en algunas cosas
var config = {
    tag: "u", 
    tiposClases: {tag: "nueva", commenthtml: "otra", 
                  attrname: "e", attrvalue: "d"},
    clases: {
        nueva: "color: green; font-weight: bold; " +
               "font-style: normal; font-size: x-large;", 
        otra: "color: maroon; padding: 0.2em; " +
              "font-family: 'Arial Black'; font-size: 1.5em; "}
};
//Segundo ejemplo pasando el argumento de la nueva configuración 
//que se modifica y/o agrega a la actual
code = wxRC.resaltar('<div id="abc">config 2</div> ' +
    '<' + '!-- CONFIG 2 --' + '>', "html", "", "", config);
document.getElementById("config2").innerHTML = code;
    

El argumento opcional config de la función resaltar() modificará aquellos valores que le pasemos. En este ejemplo modificamos el tag de resalte que era un <span> para que ahora sea un <u> que subraya el contenido. Es un elemento obsoleto en HTML5 pero que aún se siguen soportando en los navegadores y que lo pongo como ejemplo para ver el cambio. La configuración tipos de clases adjudica estilo CSS a las partes del código. El tag de HTML ahora tiene una "nueva" clase, mientras que el comentario de html (commenthtml) tiene "otra" clase. Luego en la configuración clases ponemos estilo a estas nuevas clases. Además cambiamos los estilos de nombre y valor de atributo, antes era attrname: "d", attrvalue: "e" y ahora están al revés. El resultado es un cambio en el resaltado:

Ejemplo: Modificando configuración de resalte

Podemos volver a reponer la configuración salvada (configSalvado) resaltando ahora otro ejemplo:

//Tercer ejemplo reponiendo la configuración salvada antes
code = wxRC.resaltar('<div id="abc">config 3</div> ' +
    '<' + '!-- CONFIG 3 --' + '>', "html", "", "", configSalvado);
document.getElementById("config3").innerHTML = code;
    

Ejemplo: Reponiendo configuración de resalte

La configuración de resalte que pasamos es un objeto con una o más de las variables siguientes:

VariableTipoValor inicialNotas
tagString"span"Elemento que se usará para resaltar.
comillasString"" (ninguna)Dobles ("), simples (') o ninguna.
tiposConNodosPhpObject{html: true, css: false, js: false, php: false}Declara que tipos de documentos pueden contener nodos PHP <?php ... >.
saltoString"n"Saltos de línea a incluir en el resalte, a elegir entre "r", "n", "rn", "br" que representan los saltos "\r", "\n", "\r\n", "<br>" respectivamente.
resaltadoEventosBooleantrueSi se resaltan como script el contenido de eventos en atributos HTML como onclick="alert(1)"
unificadoClasesBooleantrueEl unificado de clases reduce el código resaltado resultante.
revisadoResalteBooleantrueAl finalizar el resaltado y antes de devolverlo se puede revisar para buscar errores.
clasesObject{..., c: "color: purple; ..." , ...}Clases con cadenas de estilo CSS color, negrita, etc.
tiposClasesObject{..., tag: "c", commenthtml: "o", ...Adjudicación de clases a partes del código.
reservadasObject{js: [..., "var", ...], php: [..., "echo", ...], css: ["!important"]}Palabras reservadas de los lenguajes.
vinculosActivadosBooleantrueSi se resaltarán vínculos a URL's' en el código, en cuyo caso se usarán los dos siguientes campos.
listaVinculosString(ver nota)Ver más información en la herramienta resaltadora de código.
refVinculosString(ver nota)Ver más información en la herramienta resaltadora de código.

Descomprimir usando el módulo resaltador.js

El otro módulo que vinculamos en la página es resaltador.js, cuya única función es descomprimir un código resaltado comprimido. La herramienta Resaltador con JavaScript nos permite resaltar y comprimir un código. Genera una cadena de texto con comillas simples escapadas tal que nos permite incluir esa cadena en una variable JavaScript encerrada entre comillas simples. En este ejemplo tenemos un PRE con id="descomprime-aqui" sin contenido:

<pre id="descomprime-aqui"></pre>
...
<script>
    var wxR, wxRC;
    ...
    var comprimido = '1!$+?@^`|,span_<c!div<d ...';
    Wextensible.iniciarPagina = function() {
        ...
        wxR = Wextensible.resaltador;
        wxRC = Wextensible.resaltadorCodigo;
        wxRC.iniciar();
        ...
        //Uso de resaltador.js -----------------------------------------
        //Descomprime código y lo inserta en un elemento
        var descomp = document.getElementById("descomprime-aqui");
        wxR.descomprimir(descomp, comprimido);
    };
        window.onload = function() {
            if (Wextensible.generalJs){
                Wextensible.iniciarPagina();
            } else {
                var elemento = document.createElement("script");
                if (elemento.addEventListener){
                    elemento.addEventListener("load", Wextensible.iniciarPagina);
                } else if (elemento.readyState == "uninitialized") {
                    elemento.attachEvent("onreadystatechange", function(){
                        if (elemento.readyState == "loaded") Wextensible.iniciarPagina();
                    });
                }
                elemento.async = true;
                elemento.src = "/res/inc/general-old.js";
                var head = document.getElementsByTagName("head")[0];
                if (head) head.appendChild(elemento);
            }
        };//fin onload
</script>

La variable comprimido contiene el código resaltado y comprimido. La he acortado con puntos suspensivos ahí porque está en una única línea y es la siguiente sin saltos de línea:

var comprimido = '1!$+?@^`|,span_<c!div<d onclick><l<e="><hvar> a=<i123>; 
alert(a);<e">> $>?@1<c!b<d id><e="abc">$>ABCDE<c!/b$?!/div$?!script$><l?@1<hvar> 
a = <m"abc">;?@1<hvar> b = <i12.345>;?@1<hvar> c = <j/[a-z]*/g>;?@1<hvar> d = 
<hfunction>(){};?><c!/script$?!style$><a?@1<ddiv.miclase >{?@5<lcolor>: 
<ered>;<l?@5z-index>: <e<i5>>;?@1}?><c!/style$>';
    

Con la instrucción wxR.descomprimir(document.getElementById("descomprime-aqui"), comprimido) descomprimos el código como aparece a continuación:

Ejemplo: Código resaltado y descomprimido

Es obvio que el código resaltado ocupa más que el original. Un código tan simple como <div> se convierte en el resalte siguiente:

<span class=c>&lt;div&gt;</span>

El código original tiene 5 caracteres mientras que el resaltado tiene 32. Si lo comprimimos resulta en una cadena de 23 caracteres:

1!$*+?@^`,span_<c!div$>

Pero de esos 23 la primera parte hasta el guíon bajo es el descriptor de la compresión, siendo la propia compresion <c!div$> que ocupa 8 caracteres. En este caso no obtenemos ninguna ventaja, pues la compresión empieza a tener importancia cuando son códigos largos, obteniéndose a veces incluso tamaños comprimidos inferiores al código sin resaltar.

El módulo resaltador.js original tiene otras funcionalidades que uso en este sitio. Pero el que encontrará en el enlace de ejemplos integrados sólo expone la utilidad para descomprimir.