SCRIPT <script>

HTML401 DTD-XHTML10T DTD-XHTML10S

Es un elemento del tipo %misc que incluye los elementos mixtos que pueden actuar en bloque o en línea. Su contenido es exclusivamente datos de carácter, es decir, texto del tipo #PCDATA. En XHTML Transicional dispone además del atributo language ya desaprobado para indicar el tipo de código del lenguaje de script, pero que debe usarse el atributo type para ese cometido.

La palabra script en inglés significa "escrito" o "texto"; en términos de cine viene a expresar el "guión" de una película. En nuestro entorno XHTML podemos pensar que un script es un trozo de texto insertado o vinculado con un documento XHTML mediante el cuál ejecutamos alguna acción. Se suele usar el término script así como el plural scripts sin traducirlos, lo que también haremos aquí. Sin embargo hemos de observar que cuando señalemos la palabra script nos estaremos refiriendo al trozo de texto que representa la codificación de un programa, mientras que con <script> nos referimos al elemento de XHTML en el cual puede albergarse ese trozo de texto. Veámos algunas definiciones:

servlet
Es un programa del lenguaje Java que se ha compilado previamente y que se ejecuta en un servidor web (lado del servidor).
applet
Es un programa del lenguaje Java que se ha compilado previamente y que se ejecuta en un navegador web (lado del cliente). En la página objeto.html donde exponemos el elemento object tenemos un ejemplo con un applet.
script
Es un programa que se interpreta en el momento de ser ejecutado. Por lo tanto no requiere compilación previa. Los scripts pueden ser clasificados en los que se ejecutan en el lado del cliente, como JavaScript o VBScript (se expone aquí), y por otro lado tenemos los que se ejecutan en el lado del servidor que son los que están en la página de formulario.html. Estos scripts también se les denomina páginas de servidor. Entre ellos mencionamos JSP (Java Server Pages), PHP (Hypertext Pre-processor) y ASP (Active Server Pages).

En lo sucesivo cuando hablemos de script nos estaremos refiriendo a los que se ejecutan en el navegador del usuario. No debe confundirnos los nombres como JavaScript, pues en principio nada tiene que ver con el lenguaje Java, al igual que VBScript con VisualBasic, aunque puedan usar codificaciones similares. Aquí usaremos principalmente JavaScript para los ejemplos.

Un script convierte una página en un documento activo y/o interactivo pues puede conseguirse:

  • Se puede modificar dinámicamente una página mientras se carga para que presente su contenido adaptado a los usuarios.
  • Pueden formar parte de un formulario para verificar o revisar los datos que introduce el usuario.
  • Ejecutan las acciones de los eventos, como por ejemplo realizar alguna acción cuando pulsamos un botón.

Un script, es decir el programa escrito en texto, se incluye dentro del elemento <script> y pueden ejecutarse en un documento XHTML de dos formas:

  1. Los scripts que se ejecutan cada vez que ocurre un evento intrínseco. En este caso los elementos XHTML disponen de uno o varios atributos para eventos que ejecutan alguna acción como resultado de un script.
  2. Los scripts que se ejecutan sólo una vez cuando se carga la página. En este caso el elemento <script> no se asocia con ningún elemento y, como parte del flujo del cuerpo <body> del documento, se ejecutará cuando el navegador ejecute el elemento dentro de la carga inicial (o recarga) del flujo del documento.

A continuación se exponen algunos ejemplos ilustrativos y otras consideraciones a tener en cuenta:

  • 1 ¿Qué lenguaje de script utilizar?
  • 2 ¿Dónde incluir los scripts y como invocarlos?
  • 3 Limitaciones de los navegadores para la ejecución de scripts.
  • 4 Limitaciones de XHTML 1.0 para los caracteres <, & en los scripts internos
  • 5 Objeto window para manipular ventanas del navegador.

Ejemplo: ¿Qué lenguaje de script utilizar?

JavaScript nace en el entorno de Netscape y está soportado por la mayoría de navegadores, incluso por Explorer, aunque usa una versión denominada JScript que es básicamente la misma. Existe un estándar basado en ambos llamado ECMA-262 ( http://www.ecma-international.org/publications/standards/Ecma-262.htm), por lo cual a veces se le conoce a JavaScript como EcmaScript. Aunque la estructura de JavaScript/JScript (en lo sucesivo entenderemos ambos como JavaScript) son similares no se trata del lenguaje Java. Por otro lado tenemos VBScript, con codificación basada en VBA (Visual Basic para Aplicaciones), es otra opción para Explorer pero no soportada por otros navegadores. Y hay otras opciones, pero sin duda la más extendida, soportada y usada es JavaScript.

Por ejemplo, Visual Basic tiene una función llamada MsgBox() que presenta un mensaje en pantalla, función que puede usarse en VBScript pero la cual no existe en JavaScript, donde se dispone de la función alert() para ese cometido. En la siguiente página de ejemplo insertamos dos funciones, una en cada lenguaje, que llaman a un cuadro de mensaje desde el evento onclick de un botón mostrando la fecha actual.

...
    <title>Ejemplo js-vbs.html</title>
    <script>
        function mensajeFechaJS() {
            alert(Date())
        }
    </script>
    <script type="text/vbscript">
        Sub mensajeFechaVB()
            Msgbox(Date())
        End Sub
    </script>    
</head>
<body>
    <h1>JavaScript y VBScript</h1>
    <p><em>JavaScript</em>. La mayoría de los navegadores, 
        incluyendo Explorer mostrarán este mensaje:
        <input type="button" name="botonJS" value="alert(Date())" 
            onclick="mensajeFechaJS()" />
    </p>               
    <p><em>VBScript</em>. Sólo Explorer mostrará este mensaje:
        <input type="button" name="botonVB" value="MsgBox(Date())"
            onclick="mensajeFechaVB()" /> 
    </p>  
...
            
Resultado:
La página con el resultado es la siguiente: js-vbs.html

Ejemplo: ¿Dónde incluir los scripts y como invocarlos?

Al igual que sucedía con la aplicación de estilos CSS, donde podíamos ubicar las declaraciones de estilo como locales, internas o externas, con los scripts pasa algo similar. Como con estilos siempre es recomendable incluir los scripts en archivos externos, pues para los scripts conseguimos:

  • Si un navegador no soporta o no tiene activada la ejecución de scripts no tiene porqué sobrecargar su navegador con código de script insertado en el documento XHTML.
  • Se mejora la legibilidad del código XHTML al no tener un exceso de código script insertado.
  • Ciertas modificaciones en el script se podrían realizar externamente sin necesidad de tener que "abrir" el código XHTML.
  • Las funciones declaradas en un archivo externo pueden estar disponibles para varias páginas. Esto es importante pues si una función se usa en múltiples páginas, no habrá necesidad de duplicar su código en cada una de las páginas.
  • Es más fácil localizar el código de funciones declaradas en archivos externos, para lo cual podemos nombrar los archivos con extensión .js usando nombres que nos ayuden definir el propósito de la función o funciones similares que alberga. Esto puede resultar más fácil que intentar buscar una función que hemos incrustado en una determinada página, de entre las muchas que puede contener un sitio, y cuyo nombre de página quizás nada tenga que ver con el propósito de esa función.
  • El código interno tiene alguna limitaciones que deben considerarse según se expone en un ejemplo más abajo.

Sólo cuando el código de script de una página no es extenso y no merece tenerlo en un archivo separado, se justificaría su ubicación en la misma página. A continuación se exponen varios ejemplos muy simples pero que nos muestran donde incluir un script y como invocarlo.

1) SCRIPT INTERNO: Con el elemento <script> realizamos la ejecución del código a medida que se carga el documento. El primer ejemplo incluye un script que muestra la fecha y hora actual. Cuando el navegador sigue el flujo del documento presentando los elementos en pantalla y llega a un elemento del tipo <script>, entonces ejecutará su contenido. Cuando el script es una función de usuario que será llamada desde algún lugar del cuerpo <body> de la página, es recomendable incluir el <script> en la cabecera del documento, tal como explicamos más abajo, pues el navegador cargará la función pero no la ejecutará hasta que ésta sea llamada desde otro sitio. En este ejemplo el script no contiene una función de usuario, sino que escribe en el documento la fecha y hora actual, por lo que debe colocarse en el lugar donde se quiere reflejar ese texto, lo que se consigue con funciones estándar de JavaScript como document.write(Date()). El código del script es el siguiente:

<script>
    document.write("INTERNO = La fecha y hora actual es: "+Date());
</script>        
            
Resultado:

El resultado del Script interno:

2) SCRIPT LOCAL: Ejecución de scripts en el valor del atributo de un evento. Ahora incluimos un botón con el elemento <input>, ubicando el código del script en el valor del atributo de evento. Mediante el evento onclick llama a la función estándar de JavaScript alert(Date()) que muestra un cuadro de mensaje con el contenido de la fecha y hora actual.

<input type="button" name="boton1" value="Fecha y hora" 
    onclick="alert('LOCAL = La fecha y hora actual es: '+Date())" />        
            
Resultado:

El resultado del Script local:

¿Cómo sabe el navegador cuál es el lenguaje de script que debe usar en este caso?. La especificación dice que para evitar esto ha de incluirse una declaración en un elemento <meta> de la cabecera de la página con el contenido <meta http-equiv="Content-Script-Type" content="lenguaje">, donde lenguaje se refiere al que por defecto se usará cuando no se especifique de forma local. Pero hemos observado que incluso sin incluir esta cabecera, los navegadores consultados optan por defecto por JavaScript como lenguaje para los scripts. De todas formas es conveniente incluirlo. En cuanto a la declaración local puede ser como <script type="text/javascript"> o bien cuando forma parte del atributo de evento se declara anteponiéndolo al código, como en el ejemplo anterior que podría ponerse así: ... onclick = "javascript : alert(Date())" />. En estos dos casos locales puede obviarse si ya existe una declaración en la cabecera de la página.

Con HTML5 si falta el meta anterior o el type se entiende por defecto que es JavaScript. Últimamente (2011-2012) estoy migrando poco a poco todos los documentos de este sitio (inicialmente escritos como XHTML) a HTML5. Ya he quitado esos meta y ahora (Mayo 2012) también elimino los type del elemento cuando se declaran a JavaScript. Lo cual es siempre a excepción de algunos ejemplos con VBScript.

Por lo tanto en los ejemplos de esta página donde no encuentre type="text/javascript" para el elemento <script> es que los he eliminado pues el navegador ya entiende que por defecto es JavaScript.

Siguiendo con los scripts invocados desde un evento, también podríamos crear nuestras propias funciones y llamarlas desde un evento (a estas funciones creadas se les suele llamar funciones de usuario). En este caso introducimos una función que llamamos fechaHora() y que simplemente devuelve una cadena con "La fecha y hora actual es " + Date(). Aquí el signo más indica que concatena las dos cadenas. El mensaje se devuelve ahora desde un botón igual que el anterior, pero con el contenido alert(fechaHora()). El elemento <script> puede colocarse antes o después del botón, pues el evento no empezará a funcionar hasta que se haya cargado completamente la página y por lo tanto el navegador haya registrado la función que hemos creado. Por esta razón siempre se aconseja incluir todas las funciones de usuario en <script> ubicadas en la cabecera de la página, dentro del elemento <head> para que el navegador cargue todo el código al inicio, aunque en este ejemplo lo hemos colocado junto al botón con el evento. Este script se encuentra en el cuerpo del documento, pero no causa ningún resultado por si mismo, es decir, cuando se cargó la página al inicio y el navegador llegó a ella no ejecutó la función sino que se limitó a almacenarla. Otra cosa es si se hubiera incluido alguna función que generara contenido como document.write().

<script>
    function fechaHora(){
        return "LOCAL CON FUNCION = La fecha y hora actual es "+Date();
    }
</script>
<input type="button" name="boton2" value="Fecha y hora" 
    onclick="alert(fechaHora())" />        
            
Resultado:

El resultado del Script local con el código en una función de usuario:

3) SCRIPT EXTERNO: Todos los scripts anteriores podemos calificarlos como internos a una página. Pero también pueden ser situados de forma externa en archivos. En este ejemplo lo hemos situado en un archivo de texto llamado un-script.js (la extensión js es para JavaScript aunque admite cualquier extensión). Éste ejecuta la fecha y hora con un contenido similar a los anteriores: document.write("EXTERNO = La fecha y hora actual es: "+Date()). Mediante el atributo <script src> accedemos a ese script externo. Podría ser llamado también desde un evento, pero en este ejemplo se ejecuta con la carga del documento mediante el siguiente código:

<script src="ejemplos/script/script-externo/un-script.js"></script>                
            
Resultado:

El resultado del Script externo:

Ejemplo: Limitaciones de los navegadores para la ejecución de scripts.

Con Explorer en seguridad habilitar active scripting:

Opciones IE

Con Opera hemos de activar la siguiente opción para que se ejecuten los JavaScript:

Opciones Opera

Con Firefox hemos de activar la siguiente opción para activar JavaScript:

Opciones Firefox

Con Safari hemos de ir al menú principal

Opciones Safari

Ejemplo: Limitaciones de XHTML 1.0 para los caracteres <, & en los scripts internos

Con Explorer en seguridad habilitar active scripting:

Opciones Explorer

Con Opera hemos de activar la siguiente opción para que se ejecuten los JavaScript:

Opciones Opera

Con Firefox hemos de activar la siguiente opción para activar JavaScript:

Opciones Firefox

Con Safari hemos de ir al menú principal

Opciones Safari

Ejemplo: Limitaciones de XHTML 1.0 para los caracteres <, & en los scripts internos

Con HTML5 ya no es necesario este apartado, es decir, escapar el código dentro del elemento <script> con secciones CDATA. De hecho en esto días (Mayo 2012) he quitado todas las secciones CDATA de todos los elementos de script de todas las páginas de este sitio (realizado con una herramienta para reemplazar texto). Aunque no en este apartado, que lo seguiré dejando como estaba inicialmente. Pero entendiendo que este problema es por lo de intentar escribir el documento como un XHTML.

Como se ha señalado antes, siempre es aconsejable situar el código de script en un archivo externo. El código interno puede tener algunas limitaciones que pueden suceder en ciertas circunstancias. La especificación del DTD de XHTML 1.0 nos dice que el contenido de un script interno en el elemento <script> se incluye en el tipo #PCDATA, lo cual significa que cuando el navegador encuentre el carácter < o bien & entenderá que es el inicio de un elemento XHTML o bien que lo que continúa es una referencia a un carácter respectivamente. Tampoco podemos usar las referencias a caracteres &lt; y &amp; para referirnos a ellas, pues el navegador las pasará al script como caracteres literales. Lo aclaramos mejor con un ejemplo.

Suponga que deseamos que un script muestre en pantalla una frase en negrita tras pasar por un condicional que usamos sólo para forzar al uso de los caracteres reservados en el mismo así como dentro del contenido a presentar:

<script type="text/javascript">
    a=true; b=true;
    if (a && b) {
        document.write("<b>PLUG & PLAY</b>");
    }
</script>                
            

De esta forma el validador de XHTML nos daría un error, pues el elemento <script> no puede contener los caracteres reservados de XML como el signo de menor < y el ampersand &. Si así no funciona se nos ocurriría usar las referencias de estos caracteres &lt; y &amp; respectivamente:

<script type="text/javascript">
    a=true; b=true;
    if (a &amp;&amp; b) {
        document.write("<b>PLUG & PLAY</b>");
    }
</script>              
            

Pero ahora el problema está en JavaScript, pues el lenguaje no reconoce las referencias del caracter & cuando no es usado como texto sino para simbolizar el operador de conjunción en (a && b). Aunque si el ampersand forma parte de una cadena si puede manipularlo, pues si en lo anterior solo codificamos document.write("&lt;b&gt; PLUG&amp; PLAY&lt;/b&gt;") no usando el condicional obtendremos como resultado:

Resultado:

Como vemos, sólo conseguimos que el navegador le pase al script la referencia literal de los caracteres, no obteniendo el propósito de poner el texto en negrita. La solución que propone XHTML 1.0 es usar una sección CDATA con la forma <![CDATA[ ... ]]>. En una sección CDATA se puede incluir cualquier tipo de carácteres a excepción de la secuencia ]]> pues es la que identifica el final de la sección. Aunque de esta forma un validador de XHTML (XML) no tendrá problemas pues ignorará todo el contenido de la sección CDATA, sin embargo el motor del lenguaje de script tendrá problemas cuando encuentre los caracteres <![CDATA[ al inicio y ]]> al final. Por ello hay que marcar como comentarios para el lenguaje de script estas marcas. En JavaScript los comentarios se marcan con // al inicio de cada línea, quedando por tanto nuestro script de ejemplo como sigue:

<script type="text/javascript">
    //<![CDATA[
    var a=true;
    var b=true;
    if (a && b) {
        document.write("<b>PLUG & PLAY</b>");
    }
    //]]>
</script>                   
            

y con el siguiente resultado que mostrará el texto en cursiva y, al mismo tiempo, podrá ser validado el XHTML:

Resultado:

En resumen, una sección CDATA nos permite solucionar el problema con el uso de los caracteres <, & con páginas XHTML (basadas en XML). Como hemos dicho, XHTML 1.0 usa el tipo #PCDATA para el contenido de un <script>, pero antes para HTML 4.01 se especificaba el tipo %Script (que también servía y sirve en XHTML para el código local de los eventos). El tipo %Script, más restrictivo que #PCDATA, se define como CDATA, con el cual de forma general se reemplazan las referencias a caracteres (como por ejemplo &lt; por <), se ignoran los saltos de línea y se reemplazan los retornos de carro o tabulación con un espacio simple. Cuando el tipo CDATA se usa en algunos atributos, las restricciones sobre caracteres pueden ser incluso más fuertes. Cuando se trataba de texto en un elemento <script> el navegador debería tratar el tipo CDATA de otra forma. Por ejemplo, no podía usarse </ para que no ofreciera confusión con la etiqueta de cierra del elemento <script>. Con JavaScript se subsanaba usando el caracter de escape de la barra invertida, quedando así <\/ (esto se explica en la especificación HTML 4.01).

Por otro lado la especificación HTML 4.01 también nos dice que podemos ocultar el código de un script para que los navegadores que no los soporten no traten de representar su contenido. La propuesta es "esconder" el código en comentarios <!-- -->, para lo cual los motores de script como JavaScript estan preparados para aceptar código encerrado en su interior. Resulta que esconder el código en comentarios parece "resolver" los problemas que más arriba comentamos sobre el uso de <, &. Veámos el mismo ejemplo de antes encerrado en comentarios:

<script type="text/javascript">
    <!--
    var a=true;
    var b=true;
    if (a && b) {
        document.write("<b>PLUG & PLAY</b>");
    }                        
    //-->
</script>                
            

Ha sido necesario a su vez "esconder" a JavaScript la etiqueta de cierre del comentario, para lo cual se usa // que son los que indican a JavaScript que esa línea es un comentario (para JavaScript, no para HTML). Entonces consigue un resultado correcto:

Resultado:

Aunque el resultado es correcto en los navegadores consultados y, al mismo tiempo, hemos podido validar el XHTML pues el validador ignora los comentarios, se debe tener en cuenta la nota informativa que especifica XHTML 1.0 apéndice C.4 Embedded Style Sheets and Scripts. Viene a decir que cuando se usen los caracteres <, &, ]]>, -- se debería usar scripts externos en lugar de "esconder" el código en comentarios. Pues aunque podría resultar aceptable por los navegadores, en el fondo no es la forma de trabajar esperada para implementaciones basadas en XML. Hay que tener en cuenta que el elemento <script> espera encontrar código en caracteres #PCDATA y no comentarios, independientemente de que los motores de script sean capaces de extraer el código del interior de los comentarios. Por lo tanto si nuestra página es XHTML y con más razón incluímos el elemento que lo define como un XML al inicio con <?xml?>, entonces estamos más que obligados a usar secciones CDATA para encerrar nuestro código en el caso de que contenga <, &. Pero siempre que sea posible es recomendable situar todo el código en archivos externos.

Ejemplo: El objeto window de JavaScript

Para mostrar un poco el alcance de JavaScript podemos analizar el objeto window que nos permite manipular las ventanas del navegador. La primera parte de este ejemplo presenta como podemos abrir una página en una nueva ventana que podemos configurar usando la función window.open() con un botón para accionar el vínculo en lugar de usar un elemento <a>:

<script>
        function nuevaVentana() {
            window.open("ejemplos/script/calc/calculadora.html", "CALCULADORA",
            "toolbar=no, location=no, directories=no, status=no, menubar=no, \
            scrollbars=no, resizable=no, copyhistory=no, width=400, height=200");
        }
</script>                
<input type="button" value="Calculadora" onclick="nuevaVentana()" />          
            

Vemos que hay tres argumentos encerrados entre comillas. El primero es el destino que vamos a abrir. El segundo es un título que debería aparecer en la página. El tercero se compone de varias partes que configuran detalles como barras de herramientas y otros controles de la página así como sus dimensiones. En este caso abrimos una página llamada calculadora sobre un ejemplo que se expone en esta misma página. Veáse la barra inclinada "\" para que JavaScript ignore el salto de línea necesario para escribir el código pero que no debe formar parte del argumento. Para que funcione en los navegadores, estos deben tener activada la opción de manejar ventanas con JavaScripts. Por ejemplo, en Explorer se debe activar en Opciones, General, Pestañas, Configuración y activar, por ejemplo, Cuando se abra un elemento emergente, permitir que IE decida....

El segundo ejemplo nos permite modificar el tamaño de la ventana actual usando la función window.resizeBy(ancho, alto):

<input type="button" value="Reducir ventana" onclick="window.resizeBy(-50,-50)" /> 
<input type="button" value="Ampliar ventana" onclick="window.resizeBy(50,50)" />                
            

El último ejemplo nos pemite usar la propiedad location del objeto window para abrir un vínculo en la ventana actual:

<script>
        function abrirDestino() {
            var menSt = "La ubicación de la página actual es " + window.location; 
            menSt = menSt + " ¿Desea abrir sobre esta página la Calculadora?";
            var sino = confirm(menSt);
            if (sino == true) {
                window.location = "ejemplos/script/calc/calculadora.html";
            }
        }
</script>
<input type="button" value="Abrir calculadora" onclick="abrirDestino()" /> 
            
Resultado:

Los resultados son:

1) En este primer ejemplo mostramos el botón para acceder a la calculadora mediante una ventana abierta con script, usando la función window.open().

2) Este segundo ejemplo permite con el botón reducir el tamaño de la ventana actual unos 50 píxeles por ambos lados, mientras que con este podemos ampliarla. Usamos window.resizeBy().

3) Por último con este botón podemos abrir la calculadora en la ventana actual modificando la propiedad window.location.

Tipo de código script <script type = "x">

Con HTML5 si falta el atributto type se entiende por defecto que es JavaScript. Últimamente (2011-2012) estoy migrando poco a poco todos los documentos de este sitio (inicialmente escritos como XHTML) a HTML5. Ahora (Mayo 2012) también elimino los type del elemento cuando se declaran a JavaScript. Lo cual es siempre a excepción de algunos ejemplos con VBScript.
Este atributo, requerido, tiene como valor "x" el tipo %ContentType para indicar al navegador el tipo de código script que se va a usar. Por ejemplo text/javascript, text/vbscript, text/tcl entre otros.

Ejemplo <script type>: Tipo de código local (en atributos de eventos)

Cuando el código de script se inserta de forma local, es decir, en el atributo de evento, la forma que tiene el navegador de saber el tipo es mediante un elemento <meta> con la siguiente forma <meta http-equiv="Content-Script-Type" content="JavaScript" />. Si este encabezado no se incluye, los navegadores suelen optar por JavaScript por defecto.

Aunque la especificación no habla sobre ello, al menos para Explorer podemos declarar un tipo local anteponiéndolo al código, como en el siguiente ejemplo. Esta página que está leyendo se ha declarado con un encabezado <meta> para JavaScript. Ahora incluiremos un código en VBScript en un atributo de evento onclick para un botón:

<input type="button" name="vb" value="botón para Explorer"
onclick="vbscript:MsgBox 'Mensaje', vbYesNo+vbInformation, 'MENSAJE EN VBSCRIPT'" />
            

El tipo de código se identifica anteponiendo vbscript: al mismo, de tal forma que Explorer reconoce que el código es de Visual Basic Script y así puede mostrar el mensaje personalizado con su función MsgBox. En Visual Basic cuando una función no devuelve nada no deben usarse paréntesis para encerrar sus parámetros, que en este ejemplo son el mensaje, la configuración de botones e imágenes de información y el título del cuadro. Por supuesto, otros navegadores como Opera no actúan con VBScript, acusando un error de script o ignorando totalmente el evento cuando se pulsa el botón.

Resultado:
El botón con código en VBScript en su evento onclick es el siguiente:

Código externo de script <script src = "x">

Este atributo, requerido, tiene como valor "x" el tipo %URI para indicar al navegador cual es el archivo externo donde se encuentra el código del script. Cuando se incluye este atributo el contenido de <script> será ignorado por el navegador. Es importante señalar que la especificación dice que no es un elemento vacío, tal como vemos por ejemplo en la especificación del DTD de XHTML 1.0 Transicional:

<!-- script statements, which may include CDATA sections -->
<!ELEMENT script (#PCDATA)>
<!ATTLIST script
  charset     %Charset;      #IMPLIED
  type        %ContentType;  #REQUIRED
  language    CDATA          #IMPLIED
  src         %URI;          #IMPLIED
  defer       (defer)        #IMPLIED
  xml:space   (preserve)     #FIXED 'preserve'
  >
Observe como el atributo type es requerido en HTML-4.01 y por tanto en XHTML-1.0, pero en HTML5 ya no lo es. Por defecto toma el valor text/javascript. En todos los ejemplos de este sitio antes los incluía, pero ahora en Mayo 2012 los he eliminado para ir ajustando los documentos a HTML5.

Esto quiere decir que el elemento <script> dotado de su atributo src y todo ello incluido del documento, en <head>, debe necesariamente de incluir el tag final <script src="..."></script>, de tal forma que el elemento contiene algo (una cadena vacía). Por lo tanto usar un elemento con contenido vacío (que no es lo mismo que lo anterior) como <script src="...." /> no es válido.

Cualquier nombre para el archivo externo será válido, aunque se usan las extensiones .js para JavaScript y .vbs para VBScript por ejemplo.

Codificación de caracteres del archivo externo <script charset = "x">

Este atributo tiene como valor "x" el tipo %Charset para indicar la codificación de caracteres usados en el archivo externo, no en el contenido del elemento <script>. Recordemos que el contenido será ignorado si se incluye el atributo <script src> que indica la ruta del archivo externo donde se encuentra el código. La utilidad del atributo charset estriba en preavisar al navegador sobre el tipo de caracteres que va a encontrar en el recurso externo.

Ejemplo <script charset>

El código en JavaScript se incluye en este ejemplo en un archivo externo llamado charset.js. Simplemente contiene una cadena de texto con document.write("Generando la palabra 'CAÑÓN'") que generará la palabra "CAÑÓN". Las letras "Ñ" y el acento se codificaron en el documento usando ISO-8859-1, mientra que la página actual muestra los caracteres en UTF-8. Para evitar estas incompatibilidades se usa el atributo charset como se expone en este ejemplo.

<p>El script externo...
    <script src="/charset.js"></script>
</p>
<p>En cambio con el atributo...
    <script src="charset.js" charset="ISO-8859-1"></script>
</p>                
            
Resultado:
Ver resultado en la página de ejemplo charset.html

No genera contenido <script defer = "x">

Si se sigue la especificación de HTML 4.01, este es un atributo del tipo enumerado con el único valor defer para indicar al navegador que el script no genera contenidos, como por ejemplo con document.write en JavaScript, con lo que el navegador puede seguir construyendo la página sin necesidad de preocuparse con, por ejemplo, el espacio que va a ocupar el contenido que podría generar el script.

La información de este atributo en MSDN de Microsoft dice: "Usando el atributo en tiempo de diseño, se puede mejorar la respuesta de descarga de una página, pues el navegador no necesita analizar y ejecutar el script y puede continuar descargando y analizando la página."

La traducción de defer es diferir, y ese es su verdadero propósito: difiere la ejecución del script hasta que se complete la carga del documento, tanto los elementos HTML declarados como la carga de los mismos en el DOM de la página. En el ejemplo siguiente lo veremos.

Ejemplo <defer> para diferir la ejecución de scripts hasta que se cargue el DOM de la página

Queremos saber como este atributo difiere la ejecución del script hasta que el árbol del DOM esté completamente cargado. Para ello disponemos un primer cuadro con un bloque <div> sin nada en su interior. Luego ponemos un <script> y a continuación otro bloque <div> como el anterior. El script intentará rellenar el contenido de los dos bloques con un elemento <p> y texto mediante generación dinámica, para lo cual deberá acceder al DOM con la función document.getElementById("...") y generar el nuevo elemento con innerHTML. Hacemos dos páginas con el mismo código, una usando el atributo defer="defer" y otra sin usarlo (que equivale a decir que defer = false).

<p>Aquí hay...</p>
<div id="conten1" style="border: red solid 1px;"></div>

<p>Después de esto viene...</p>     
<script defer="defer"> (o sin defer para el otro caso)
       document.getElementById("conten1").innerHTML = 
           "<p style='border: green solid 1px; color: green;'>ABC</p>";
       document.getElementById("conten2").innerHTML = 
           "<p style='border: green solid 1px; color: green;'>ABC</p>";		        
</script>

<p>Aquí hay...;/p>  
<div id="conten2" style="border: red solid 1px;"></div>    

Sin usar defer el script podrá localizar el bloque anterior identificado como id="conten1" pues ya pasó por él y lo cargó en el DOM. Pero no podrá localizar el segundo bloque id=conten2 pues éste aún no ha sido cargado en el DOM. El segundo bloque no contendrá nada y, si tenemos los avisos de errores de script activados, saltará el error en ese momento antes de seguir "pintando" el resto de la página.

Usando defer la ejecución del script se deja para el final, es decir, para cuando todos los elementos han sido ya presentados visualmente y cargados en el DOM. Con ello ya puede el script encontrar todas las referencias a elementos en la página y rellenar los <p> dentro de los <div> vacíos.

Hemos observado que se ejecuta correctamente en Explorer 8 y en Firefox 3.5, pero no en Opera 10.53 ni en Safari 4.0, lo que significa que no difieren la ejecución del script con el uso de defer.

Dado que no todos los navegadores lo soportan, la mejor opción es usar el evento onload referido al objeto body, de tal forma que todo el script incluido en ese evento sólo será ejecutado cuando la página finalice su carga tanto visual como en el DOM. Alternativamente puede usar una función anónima para el objeto window.

Preservar espacios <script xml:space = "x">

XML10 Este atributo, como todos los que empiezan por xml:, es específico de XML. Supone preservar los espacios en blanco. Viene definido en el DTD como un tipo enumerado con un único valor preserve. Además se declara #FIXED y, como sólo tiene un valor, se le dota de valor por defecto el mismo preserve. Por lo tanto no es necesario manejarlo pues dota al elemento con la función de preservar los espacios por defecto.

CONTENIDO NO SCRIPT <noscript>

HTML401 DTD-XHTML10T DTD-XHTML10S
Elemento del tipo %Block para incluir contenidos XHTML que serán presentados en el caso de que el navegador no soporte o no tenga activada la ejecución de scripts.

Ejemplo <noscript>

La especificación dice que se presentará el contenido de <noscript> en los casos:
  • Cuando se desactive la ejecución de scripts en el navegador
  • Cuando el navegador no soporta un lenguaje de script invocado por un elemento de <script> anterior en el documento.
En este ejemplo ponemos un <script> con un lenguaje ficticio, con lo cual no se ejecutará el script. El objeto es forzar al navegador a presentar el contenido alternativo que ponemos a continuación.
<script type="text/XYZScript">
    //comentario
</script>
<noscript>
    <p>Su navegador no soporta <em>XYZScript</em> o 
    bien se ha desactivado la ejecución de scripts.</p>
</noscript>
            
Resultado:

Resultado con un script en un lenguaje inexistente y un contenido alternativo que debería presentarse a continuación:

En los navegadores consultados sólo aparece el contenido alternativo si desactivamos la opción de no ejecutar scripts.

EVENTOS <E evento>

HTML401 DTD-XHTML10T DTD-XHTML10S

Representando <E> un elemento, el valor del atributo evento es del tipo %Script que viene a ser un tipo final CDATA, donde incluímos el código script que será ejecutado cuando se produzca el evento. Siguiendo el DTD de XHTML estricto, los eventos se clasifican como sigue:

  • Eventos generales del tipo %events o también %attrs que incluye el tipo anterior (DTD-XHTML10T DTD-XHTML10S), que pueden encontrarse en casi todos los elementos, por lo que resulta más fácil indicar los elementos que NO disponen de estos eventos que son <br> y <param>. Se trata de eventos que captan las pulsaciones del ratón o de teclas.
  • Eventos de foco del tipo %focus (DTD-XHTML10T DTD-XHTML10S) que se encuentran con los elementos que pueden obtener el foco y que son <a>, <area>, <label>, <input>, <select>, <textarea>, <button>.
  • Eventos de página del elemento <body>, que suceden cuando se carga o descarga una página.
    • <E onload>, cuando se finaliza la carga de una ventana.
    • <E onunload>, cuando se elimina un documento de una ventana.
  • Eventos de formulario que se encuentran en algunos de los elementos propios de un formulario: <form>, <input>, <select>,<textarea>

Evento cuando se pulsa el ratón sobre un elemento. <E onclick = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se pulsar el ratón sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onclick

Evento al pulsar el ratón sobre un elemento. También actúa cuando el elemento tiene el foco, entre aquellos elementos que pueden obtenerlo, y se pulsa la tecla Enter. En la segunda parte de este ejemplo queremos llevar el foco a un botón. Se mostrará un borde punteado en el botón cuando tenga el foco, en cuyo momento podemos activar el evento onclick también con la tecla Enter
<p>Un elemento 
    <span onclick="alert('Evento onclick')"
    style="border: solid 1px;">SPAN</span> 
    que actúa con...
</p>
<p>
    Dirigiendo el foco a este
    <input type="button" name="botonclick" 
    onclick="alert('Evento onclick')" value="botón" /> 
    puede actuar...
</p>  
            
Resultado:

Un elemento SPAN que actúa con el evento onclick si se usa el ratón mostrando un mensaje.

Dirigiendo el foco a este puede actuar también con el evento onclick también mediante la tecla enter.

Una forma rápida de dirigir el foco a un botón sin pulsarlo es seleccionar un trozo de texto previo deslizando el puntero del ratón y luego pulsar la tecla de tabulación, aunque no funciona con Safari.

Evento cuando se pulsa dos veces el ratón sobre un elemento. <E ondblclick = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se pulsar el ratón dos veces sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento ondblclick

Evento al pulsar dos veces el ratón sobre un elemento <span> que contiene texto.
<p>Un elemento <span ondblclick="alert('Evento ondblclick')" 
    style="border: solid 1px;">SPAN</span> que actúa...
</p>
<p>Un elemento imagen....
</p>                
<div style="border: solid 1px; width: 30px; ">
    <img ondblclick="alert('Evento ondblclick')" style="margin: 5px;" 
    src="ejemplos/script/img_1.jpg" width="16" height="16" alt="img_1.jpg" />
</div>
            
Resultado:

Un elemento SPAN que actúa con el evento ondblclick mostrando un mensaje.

Un elemento imagen que actúa con el evento ondblclick mostrando un mensaje, pero que se sitúa en un bloque que no contiene texto:

img_1.jpg

Con Opera ha tenerse en cuenta que se usa el doble click en elementos de texto para seleccionar una palabra completa, tras lo cual ofrece un menú contextual que pemite entre otras cosas traducir o buscar en un diccionario ese texto, como tiene otros navegadores, pero que no interfiere con el doble click. Así con Opera saldrá primero nuestro script y luego aparecerá ese menú contextual.

Evento cuando baja el ratón <E onmousedown = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se pulsar una tecla del ratón sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onmousedown

Evento cuando se pulsa una tecla del ratón sobre un elemento. En este caso sólo actúa cuando se pulsa el botón del ratón, lo cual es conveniente si no queremos captar la tecla Enter usando el evento onclick.
<p>Un elemento 
    <input type="button" name="botomousedown" 
    onmousedown="alert('Evento onmousedown')" value="botón" /> 
    que actúa...
</p>
            
Resultado:

Un elemento que actúa con el evento onmousedown mostrando un mensaje cuando baja el botón, pero que no actúa con la tecla Enter como sucedía con el evento onclick.

Evento cuando sube el ratón <E onmouseup = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se suelta una tecla pulsada en el ratón. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onmouseup

Evento cuando se suelta una tecla del ratón. En principio un elemento debería poder aceptar varios eventos. En este ejemplo incluimos los eventos onmousedown cuando baja una tecla del ratón y onmouseup cuando sube. Netscape interpreta ambos eventos y produce dos mensajes. Opera y Explorer sólo captan el mensaje de bajada del ratón.
<p>
    Un elemento
    <span onmousedown="document.getElementById('md').innerHTML = 'MOUSE-DOWN';" 
    onmouseup="document.getElementById('mu').innerHTML = 'MOUSE-UP';" 
    style="border: solid 1px;">SPAN</span>
    que actúa ... Puede repetir ... con este botón: 
    <input type="button" value="borrar" 
    onclick="document.getElementById('md').innerHTML = '&nbsp;'; 
    document.getElementById('mu').innerHTML = '&nbsp;';" />
</p> 
<div id="md" style="border: red solid 1px;"> </div>
<div id="mu" style="border: red solid 1px;"> </div> 
            
Resultado:

Un elemento SPAN que actúa con el evento onmousedown mostrando el texto "MOUSE-DOWN" en el primer cuadro mientras se mantenga presionada la tecla y luego, cuando se suelta, mostrará "MOUSE-UP" en el otro cuadro mediante el evento onmouseup. Puede repetir la prueba borrando el contenido de los cuadros con este botón:

 
 

Evento cuando se sitúa el ratón <E onmouseover = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se sitúa el ratón sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onmouseover

Evento cuando se sitúa el ratón en un elemento. Usando el argumento this para llamar a una función que hemos creado para cambiar el color de fondo de un elemento accediendo a sus propiedades de estilo. Se debe tener en cuenta que con la propiedad de estilo {background-color} y otras que lleven un guión en medio, ha de eliminarse este guión y poner la siguiente letra en mayúsculas. En el condicional donde se compara fondo con un color, Opera solo reconoce el valor hexadecimal, por lo que hemos puesto ambas posibilidades (color aqua le corresponde el valor #00ffff, con letras en minúsculas para que lo pueda aceptar Opera).
<script>
    function cambiaFondo(elemento){
         var fondo = elemento.style.backgroundColor;
         if ((fondo == "aqua")||(fondo == "#00ffff")) {
            elemento.style.backgroundColor = "white";
          } else {
            elemento.style.backgroundColor = "aqua";
        }
    }
</script>
<p>Un elemento 
    <span onmouseover="cambiaFondo(this)" style="border: solid 1px;">
        Span con fondo cambiante
    </span>
    que cambia de color...
</p>
            
Resultado:

Un elemento Span con fondo cambiante que cambia de color al salir y entrar con el ratón.

Evento cuando se mueve el ratón <E onmousemove = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se mueve el ratón sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo con el evento onmousemove: uso de las palabras claves this y event.

Este ejemplo no tiene mucha utilidad, pero nos muestra algunos detalles. Por un lado podemos usar la propiedad de evento para cambiar dinámicamente las propiedades de estilo. En este caso cambiamos el color de fondo de un bloque <div> al mover el ratón sobre el mismo. Para ello usamos en ese elemento onmousemove="this.style.backgroundColor=cambiaColor(this, event)" donde se llama a la función cambiaColor(this, event) observándose que:

  1. La palabra clave de JavaScript this hace referencia al propio elemento donde está situado el evento. Esta referencia luego, dentro de la función, nos servirá para acceder a una de sus propiedades, su posición izquierda con offsetLeft.
  2. La palabra clave event hace referencia al manejador de eventos de la ventana, es decir a window.event, de tal forma que en la función podremos acceder a su propiedad clientX que nos da la posición horizontal del cursor del ratón en la ventana (no en el elemento donde se originó el evento).

También ejecutamos en la función la selección de otro elemento mediante el uso de var miSpan = document.getElementById("unspan"), para luego cambiarle el color y poner el número que indica la posición desde el borde izquierdo del elemento que señala en ese momento el cursor.

<script>
    function cambiaColor(elemento, eventoEntrada) {
        var izquierda = elemento.offsetLeft;
        var x = eventoEntrada.clientX - izquierda;
        var miColor = "white";
        if (0<x && x<=30) {
            miColor = "navy";
        } else if (30<x && x<=60) {
            miColor = "blue"; 
        } else if (60<x && x<=90) {
            miColor = "aqua";
        } else if (90<x && x<=120) {
            miColor = "purple";
        } else if (120<x && x<=150) {
            miColor = "red";
        } else if (150<x && x<=180) {
            miColor = "orange"; 
        } else if (180<x && x<=210) { 
            miColor = "yellow";   
        } else if (210<x && x<=240) { 
            miColor = "green";   
        } else {
            miColor = "lime";
        }
        var miSpan = document.getElementById("unspan");
        miSpan.style.borderColor=miColor;  
        miSpan.innerHTML = x;
        return miColor;
    }
</script>
<p>Este elemento...
</p>
<div style="border: solid 1px; width: 240px; height: 30px " 
    onmousemove="this.style.backgroundColor=cambiaColor(this, event)"
    onmouseout="this.style.backgroundColor='white'">
</div>
<p>Este elemento ...
<span id="unspan" style="border: solid 4px; height: 10px">SPAN</span> 
...
</p>
            
Resultado:

Este elemento <div> cambia el color del fondo cuando nos movemos con el ratón en sentido horizontal:

Este elemento <span> cambiará también el color de su borde SPAN al mismo tiempo, incluyendo en su interior la posición horizontal del ratón.

Evento cuando el ratón sale de un elemento <E onmouseout = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando el ratón sale de un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onmouseout

Una forma para cargar una página con imágenes pequeñas a modo de iconos y luego según el usuario lo desee ampliar las mismas. Disponemos de 4 fotos de 38x51 píxeles que incluimos juntas en la misma línea. Cuando el ratón entra en una imagen con onmouseover se llama a una función zoom(this), pasando en el argumento la referencia al elemento. Luego en el script extraemos el valor de un zoom que el usuario puede seleccionar mediante un cuadro desplegable. Con document.getElementById("nZoom").value extraemos ese valor. El ancho y alto máximo de cada foto es de 384x512 píxeles, todas del mismo tamaño. Por lo tanto dividimos el máximo por el valor de zoom introducido y, según la foto desde donde hemos accedido a la función, aplicamos ese tamaño así como la foto original en tamaño grande. Como vemos, la función no retorna nada sino que cambia los atributos de la imagen desde la propia función, pues su argumento es una referencia a la misma.

Cuando salimos de una foto con onmouseout volvemos a poner la imagen original con onmouseout="this.src='script/fotochica1.jpg'; this.width='38'; this.height='51'", incluyendo el código necesario dentro del propio atributo de evento.

<script>
    function zoom(imagen){
        var numZ=document.getElementById("nZoom").value;
        imagen.width = 384/numZ;
        imagen.height= 512/numZ;
        switch (imagen.id) {
            case "foto1": imagen.src="ejemplos/script/fotogrande1.jpg";break;
            case "foto2": imagen.src="ejemplos/script/fotogrande2.jpg";break;
            case "foto3": imagen.src="ejemplos/script/fotogrande3.jpg";break;
            case "foto4": imagen.src="ejemplos/script/fotogrande4.jpg";break;
        }
    }
</script>
<p>
<label>Seleccione el zoom que desee para ampliar la foto:
    <select name="nZoom" id="nZoom">
        <option value="1">x 10</option>
        <option value="2">x 5</option>
        <option value="3" selected="selected">x 3.33</option>
        <option value="5">x 2</option>
        <option value="8">x 1.25</option>
    </select>
</label><br />
<img 
id="foto1" src="ejemplos/script/fotochica1.jpg" width="38" height="51" alt="foto1"
onmouseover="zoom(this)" 
onmouseout="this.src='ejemplos/script/fotochica1.jpg'; this.width='38'; this.height='51'" 
/><img 
id="foto2" src="ejemplos/script/fotochica2.jpg" width="38" height="51" alt="foto2"
onmouseover="zoom(this)"
onmouseout="this.src='ejemplos/script/fotochica2.jpg'; this.width='38'; this.height='51'" 
/><img 
id="foto3" src="ejemplos/script/fotochica3.jpg" width="38" height="51" alt="foto1"
onmouseover="zoom(this)"
onmouseout="this.src='ejemplos/script/fotochica3.jpg'; this.width='38'; this.height='51'" 
/><img 
id="foto4" src="ejemplos/script/fotochica4.jpg" width="38" height="51" alt="foto1"
onmouseover="zoom(this)"
onmouseout="this.src='ejemplos/script/fotochica4.jpg'; this.width='38'; this.height='51'" 
/>                    
</p>                
            
Resultado:


foto1foto2foto1foto1

Evento cuando se pulsa una tecla <E onkeypress = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se pulsa una tecla cualquiera sobre un elemento. Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onkeypress para validar números en un cuadro de texto

Evento cuando se pulsa una tecla. Una de las utilidades de este evento puede mostrarse con un campo de texto <input> donde queremos controlar que sólo se introduzcan cuatro números. La longitud del campo es fácil limitarla con el atributo maxlength. Para controlar que sólo se tecleen números hemos de usar un script. Aunque no pretendemos introducirnos demasiado en el lenguaje JavaScript, intentaremos explicar brevemente el funcionamiento de un script que realizaría este control.

Con eventos como onkeypress, onclick y onsubmit se puede retroceder la acción del usuario que provocó el evento si éste devuelve un valor false. En otro caso si no devuelve falso, es decir, si devuelve cualquier cosa que no sea false, entonces el evento proseguirá su curso. Veámos un ejemplo:

<p>En este control...
    <input type="text" onkeypress="return false" />
</p>
<p>En cambio en este control...
     <input type="text" onkeypress="return true" />, ...
</p> 
            
Resultado:

En este control no podrá introducir ningún carácter, pues cada vez que se pulsa una tecla se devuelve falso y el carácter no pasará al cuadro de texto:

En cambio en este control con un evento que no devuelve false si lo podrá hacer: , lo que equivale a un control de texto donde no se incluya el atributo de evento o éste, si se incluye, devuelva otra cosa que no sea false.

Aprovechando esta característica podemos controlar los caracteres que se introducen en un campo de texto. Desde el control usamos la función que hemos creado compruebaNum(eventoEntrante), donde el argumento trae la referencia al manejador de eventos window.event. Una propiedad de este objeto event es el código ASCII del carácter de una tecla pulsada. Nos encontramos con el problema de que con Explorer hay que extraerlo con keyCode y para otros navegadores con charCode, lo cual salvamos poniendo código alternativo var codigoAscii = eventoEntrante.charCode || eventoEntrante.keyCode. Una vez tengamos el código ASCII, lo convertimos en un caracter con la función String.fromCharCode(). Luego la comparamos con la cadena "0123456789" para ver si la tecla pulsada no es alguno de los números en cuyo caso nos devolvería -1, devolviendo entonces false y no permitiendo volcar el carácter no numérico en el cuadro de texto.

 <script>
    function compruebaNum(eventoEntrante){
        var codigoAscii = eventoEntrante.charCode || eventoEntrante.keyCode;
        var caracter = String.fromCharCode(codigoAscii);
        var numeros = "0123456789";
        return numeros.indexOf(caracter) != -1;
      }
 </script>
<p>Introduzca el año...
    <input type="text" name="anyo" maxlength="4" 
    onkeypress="return compruebaNum(event)" />
</p> 
            
Resultado:

Introduzca el año (4 dígitos numéricos):

En JavaScript existe la función isNaN(argumento) para saber si el argumento es un número devolviendo true en ese caso o false en caso contrario. Sin embargo también confirmará como número los decimales y otros formatos de números.

Ejemplo: Evento onkeypress para limitar el tamaño máximo de un cuadro de texto de múltiples líneas.

El evento de teclado onkeypress tiene una gran utilidad para validar los datos que se introducen en los campos de un formulario. Por ejemplo, el control <input> con el tipo text nos permite introducir texto en una línea y limitar su tamaño con el atributo maxlength a un número determinado de caracteres. Sin embargo el control <textarea> para introducir texto en múltiples líneas no tiene forma de limitar el tamaño. Este ejemplo se destina a ello.

En el atributo de evento del cuadro de texto devolvemos el resultado true, false de una función que hemos creado, llamándose con llegoFin(this, event, 10). El primer argumento es una referencia al elemento. El segundo nos permite referenciar el evento para luego obtener el código ASCII de la tecla pulsada. El último argumento es el tamaño máximo de caracteres que podemos introducir en el cuadro de texto.

En la función extraemos la longitud actual del cuadro de texto con elemento.value.length. Si no supera el tamaño devolvemos true y el usuario podrá seguir tecleando caracteres. Si supera el tamaño máximo podemos permitir que el usuario pueda pulsar las teclas de retroceso, suprimir o las flechas de dirección. Estas tienen los valores ASCII 8, 37, 38, 39, 40 y 46, que son introducidos en el array teclas. Captamos el código ASCII de la tecla pulsada de la misma forma que lo expuesto en el ejemplo de validación de números. Luego comprobamos si esa tecla está en el array, en cuyo caso la permitimos devolviendo true, en otro caso devolvemos false.

<script>
        function llegoFin(elemento, eventoEntrante, maximoTamanyo){
            var longitud = elemento.value.length;
            if (longitud > maximoTamanyo) {
                var codigoAscii = eventoEntrante.charCode || eventoEntrante.keyCode;
                var teclas = [8, 37, 38, 39, 40, 46];                          
                for (i in teclas){
                    if (codigoAscii == teclas[i]) {
                        return true;
                    }
                }                           
                return false;
            } else {
                return true;
            }
        }
</script>
<label>
    <textarea name="muchotexto" rows="6" cols="15"
    onkeypress="return llegoFin(this, event, 10)" ></textarea>
</label>
            
Resultado:

El cuadro anterior es multi-línea, con lo que puede incluir retornos de carro, los cuales también cuentan como caracteres a la hora de calcular el tamaño.

Este script no impide pegar un texto más largo, lo cual debería hacerce con otro método.

Evento cuando una tecla baja <E onkeydown = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se pulsa una tecla cualquiera sobre un elemento (momento en el que la tecla baja). Puede incluirse en todos los elementos excepto <br> y <param>.

Evento cuando una tecla sube <E onkeyup = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se suelta una tecla cualquiera sobre un elemento (momento en el que la tecla sube). Puede incluirse en todos los elementos excepto <br> y <param>.

Ejemplo: Evento onkeyup. Controlando entradas de texto en un control de formulario

Evento cuando se suelta una tecla. En este ejemplo hacemos uso del evento onkeyup para detectar que se ha tecleado cierta palabra en un control de texto. Usamos un control de tipo contraseña y verificamos la misma en un script. Se observa el uso de this como argumento de llamada de la función con lo cual se está pasando una referencia al elemento <input>, tal que luego en el script podemos extraer su atributo valor con elemento.value y compararlo con la contraseña "1234" que sería la correcta. Por supuesto esto es sólo un ejemplo para el uso del evento, pues el nivel de seguridad es muy elemental.
<script>
    function confirmaCntr(elemento){
        if (elemento.value == "1234") {
            alert("La contraseña es correcta: '1234'");
            //aquí se realizaría el proceso permitido
        }
    }
</script>
<p>Introduzca contraseña: 
    <input type="password" name="textbox" onkeyup="confirmaCntr(this)" />
</p>
            
Resultado:

Introduzca contraseña:

Evento cuando se obtiene el foco <E onfocus = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando un elemento obtiene el foco. Puede incluirse en elementos capaces de captar el foco como <a>, <area>, <label>, <input>, <select>, <textarea> y <button>.

Ejemplo: Evento onfocus. Pasando el foco a controles de formulario

Aquí presentamos un formulario con controles y un elemento de texto que sirve como notas destinadas al usuario para explicar como debe rellenar el formulario. Con el evento onfocus obtenemos el identificador del elemento al pie para dotarle del comentario que deseemos usando innerHTML, el cuál modifica el contenido del elemento.

<form style="border: solid 1px;">
    <label>Nombre: 
        <input type="text" name="campo1" size="100"
        onfocus="document.getElementById('este-pie').innerHTML=
        'Nota: Introduzca el nombre y dos apellidos'" />
    </label><br />
    <label>Dirección: 
        <input type="text" name="campo2" size="100"
        onfocus="document.getElementById('este-pie').innerHTML=
        'Nota: Dirección completa, con el número, bloque, portal, etc.'" 
        />
    </label><br />
    <label>Fecha de nacimiento: 
        <input type="text" name="campo3" size="10"
        onfocus="document.getElementById('este-pie').innerHTML=
        'Nota: Fecha con el formato dd/mm/aaaa'" 
        />
    </label><br />                    
    <span id="este-pie" style="font: italic 0.8em 'Arial';">Nota:</span>
</form>
            
Resultado:



Nota:

Evento cuando se pierde el foco <E onblur = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando un elemento pierde el foco. Puede incluirse en elementos capaces de captar el foco como <a>, <area>, <label>, <input>, <select>, <textarea> y <button>.

Ejemplo: Evento onblur. Botones con script

Podemos denominar a un vínculo con imagen como un "botón" en el sentido de que es capaz de ejecutarse algo cuando hacemos "click" en la imagen. Añadir una imagen a un vínculo es sencillo, por ejemplo con una imagen de 32x32 píxeles podemos formar el siguiente vínculo con imagen Icono, cuyo código es

<a id="aqui-mismo"/><a href="#aqui-mismo"><img 
src="ejemplos/script/boton-script/pyramid.gif"alt="" /></a>
            

Aprovechando esta utilidad podemos mejorarla dotándo a este botón con estilos, dándole un fondo y un borde personalizado. Para ello usamos la imagen de 32x32 píxeles para el fondo y que personaliza un borde con esquinas redondeadas Fondo, el cual hemos creado con facilidad con cualquier editor de imágenes, que combinada con la imagen del botón formamos botón como un botón de vínculo. El código para esto es:

<a id="aqui-tambien"/><a href="#aqui-tambien"><img 
src="ejemplos/script/boton-script/pyramid.gif" alt=""
style="background-image: url(ejemplos/script/boton-script/fondo.gif); 
background-repeat: no-repeat; border: 0" /></a>                
            

Es conveniente observar que en el código no puede haber espacios, ni siquiera saltos de línea, entre el elemento imagen y el vínculo que lo encierra, con el objeto de que la imagen se ajuste perfectamente al fondo y, por otro lado, el vínculo <a> se ajuste al tamaño de la imagen. Observe que la imagen del botón tiene el fondo de color transparente, lo que puede hacerse con el formato gif, para que deje entrever detrás a la imagen con bordes redondeados, que a su vez también es transparente para dejar entrever el fondo de la página.

La propuesta es darle un toque dinámico a este botón, de tal forma que cuando el usuario entre con el ratón o con el tabulador, el botón se "encienda" de alguna forma. Hemos elegido la imagen botón para ello, que es la misma que la del fondo pero dándole un color. Así el botón "encendido" quedará botón. El siguiente paso es hacer uso de los eventos y script necesarios para realizar este efecto. El elemento <a> dispone de los eventos onfocus, onblur para cuando obtiene y pierde el foco respectivamente, pero el elemento <img> no puede obtener el foco. Como el fondo o resalte del botón hay que aplicarlo a la propiedad {background-image}, del elemento imagen, hay que tener en cuenta que cuando el elemento vínculo recibe los eventos onfocus, onblur debe trasladar la accion al elemento imagen. Por otro lado los eventos onmouseover, onmouseout detectan cuando el ratón entra o sale de un elemento, pudiendo ser generados tanto por el vínculo como por la imagen. En nuestro caso aplicarán también la propiedad {background-image} al elemento imagen, por lo que captaremos estos eventos desde ese elemento. El código para encender o apagar un botón sería:

<a href="pyramid.gif" onfocus="manejarBoton(document.getElementById('bot1'), 'on')"
onblur="manejarBoton(document.getElementById('bot1'), 'off')"         
><img class="bot" id="bot1" src="pyramid.gif" alt="" title="Imagen 'pyramid.gif'"
width="32" height="32" onmouseover="manejarBoton(this, 'on')" 
onmouseout="manejarBoton(this, 'off')" /></a>                
            

Por un lado el elemento vínculo al obtener o perder el foco acciona la función manejarBoton(a,b) para encender o apagar el botón, pasando como argumentos una referencia al elemento imagen y un valor "on" o "off" según el caso deseado. Por otro lado el elemento imagen capta los eventos con el ratón y ejecuta directamente la misma función, pero pasándose a sí mismo como referencia (con this). El script de la función se describe a continuación:

function manejarBoton (boton, onoff){
    if (onoff == "on"){
        boton.style.backgroundImage = "url(resalte.gif)"
    } else {
        boton.style.backgroundImage = "url(fondo.gif)"
    }
}

Como vemos, en el primer argumento traemos la referencia al elemento adecuada (vínculo o imagen), mientras que en el segundo argumento nos dice si hemos de resaltar el botón con la imagen "resalte.gif" o apagar el botón con "fondo.gif". Para completar el tema se incluyen todos los botones (3 en este ejemplo) dentro de un bloque dotado de un color de fondo para visualizar el efecto, lo cual puede observar en el código completo de la página.

Por último queremos indicar que si una página contiene un gran número de estos botones, puede resultar engorroso tanto código en la página. Una forma de "limpiar" de código script una página es aplicando los manejadores de eventos semánticos y las funciones anónimas mediante el uso del evento onload. Este mismo ejemplo se desarrolla de esta forma en otro ejemplo expuesto más abajo en la descripción del evento onload.

Resultado:
La página de resultado es la siguiente: boton-script-1.html

Evento cuando la página completa su carga <E onload = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando un página finaliza su carga. Sólo puede incluirse en el elemento <body>.

Cuando un script hace referencias a elementos de la página como por ejemplo con getElementById(), si se ejecuta el script y la página aún no ha completado su carga es posible que se produzca un error al no encontrar ese elemento. Por esa razón existe el evento onload, que se produce cuando se finaliza la carga y lo cual podemos aprovechar para realizar las acciones que deseemos.

En este apartado incluiremos los siguientes ejemplos que, haciendo uso de una forma de cargar los eventos de los elementos con el evento onload de la página, aprovechamos para mostrar de forma superficial otras utilidades de JavaScript:

El "layout" o enmaquetado de las páginas de un sitio y más especialmente de la página de inicio es un tema importante. Antes se realizaba con tablas, pero la aparición de CSS ha promovido otras formas de confeccionar las páginas, y más exactamente los marcos y menús de selección que permiten navegar al usuario por el sitio. Los scripts ofrecen alternativas sin límite. En otros lugares ya hemos presentado una página de inicio con marcos realizados mediante CSS, como el ejemplo marcos de página, donde se aprecia que no se han usado los elementos <frame> que se convertirán en obsoletos en un futuro.

Otro elemento importante son los menús. Confeccionados con elementos de listas, CSS y pseudoclases de vínculo tenemos también el ejemplo de un menú lateral. Ahora proponemos combinar los marcos CSS y una nueva forma de presentar menús laterales con CSS y scripts. El siguiente código representa la página de inicio de un sitio de ejemplo, aunque todas las páginas del sitio que se enlazan con el menú del inicio se configuran igual. El esquema básico de la página son tres divisiones con clases cabecera, menu y contenido. Todas las páginas enlazan al mismo código JavaScript en el archivo manejamenu.js, que luego explicaremos. Las únicas diferencias que hay entre las páginas del sitio son (en negrita en el código):

  • Por supuesto, la información propia de cada página, como puede ser el título en la división de cabecera o la división contenido con la información propia de esa página.
  • Los argumentos de una función en el script incluidos en el atributo onload del cuerpo <body> de cada página.

Por lo tanto la división menu es la misma para todas las páginas, siempre y cuando se desee repetir este menú en todas las páginas. El menú se realiza con vínculos y divisiones, a los cuales se les dota de estilos, como al resto de la página, con el archivo externo base.css. Una entrada del menú la identificamos con marcomenuN, donde "N" representa un número de 0 en adelante siendo el cero para la página de inicio. Dentro ponemos el vínculo a la página identificado con menuN. Vemos que id="marcomenu0" y id="menu0" son los que corresponden al menu inicio. A continuación la siguiente entrada es id="marcomenu1", cuyo vínculo no nos lleva a ninguna página, sino a unas subentradas relacionadas en id="listamenu1". Luego cada subentrada ya nos dirige a los lugares definitivos.

...
    <script src="manejamenu.js"></script>
</head>
<body onload="muestraMenu(document.getElementById('menu0'), false); poneFecha()">
    <div class="cabecera">
        <div class="linea1">
            INICIO
        </div>
        <div class="linea2" id="fechaHoy"></div>
    </div>
    <div class="menu">
        <div id="marcomenu0" style="border: 0;">
            <a id="menu0"  href="index.html" 
            onclick="muestraMenu(this, false)" >Inicio</a><br />
        </div>           
        <div id="marcomenu1" style="border: 0;">
            <a id="menu1"  href="#listamenu1" 
            onclick="muestraMenu(this, true)">Productos</a><br />
            <div id="listamenu1" class="listamenu" style="display: none;">
                <a href="productos.html#mesas">Mesas</a><br />
                <a href="productos.html#sillas">Sillas</a><br />
                <a href="productos.html#varios">Varios</a><br />
            </div>            
        </div>
        ....siguen otras entradas de menú
    </div>
    <div class="contenido">
        contenido de la página de Inicio
        ....
            

Cada entrada de menú tiene un script en su atributo de evento onclick que configura visualmente esa entrada usando la función muestraMenu(a,b). El argumento "a" es una referencia a un elemento de la página, para luego tener acceso a él desde la función. El argumento "b" es un booleano que nos dice si la entrada del menú tiene una lista de submenús o no. Esta función también se invoca con el evento onload cuando la página se haya cargado completamente. El código del script en el archivo externo se reproduce a continuación:

//En cada página se crean dos variables globales para controlar cual
//es el marco de menú de entrada y la lista de submenús que se han desplegado
var marcoDesplegado = "";
var listaDesplegada = "";
function muestraMenu(elemento, conLista){
    //Antes de tratar una nueva entrada de menú, plegamos marcos y lista
    //que estuvieran desplegadas antes
    if (marcoDesplegado != "") {
        document.getElementById(marcoDesplegado).style.border="0"
    }
    if (listaDesplegada != "") {
        document.getElementById(listaDesplegada).style.display="none"
    }
    //Nombramos el nuevo marco de entrada de menú
    marcoDesplegado = "marco"+elemento.id
    //Le añadimos un borde para saber que ha sido pinchado
    document.getElementById(marcoDesplegado).style.border="green solid 1px"
    //Si la entrada tiene una lista de submenús, entonces la desplegamos
    if (conLista) {
        listaDesplegada = "lista" + elemento.id
        document.getElementById(listaDesplegada).style.display="block"
    } else {
        listaDesplegada = ""
    }
}

//Esta función se limita a poner la fecha actual en un elemento cuyo id sea
//igual a "fechaHoy"
function poneFecha(){
    document.getElementById("fechaHoy").innerHTML = Date()
}                
            

Los comentarios incluidos en el código así como observar el resultado deben ser suficientes para su entendimiento. En definitiva se trata de poner un borde a cada entrada de menú y desplegar el submenú si esa entrada lo tuviera, plegando en su caso otros submenús que estuvieran abiertos previamente.

Pero también la función muestraMenu(a,b) se ejecuta con el evento onload en la carga de la página. La razón de ello es que cuando accedemos a una página debe mostrarse resaltado la entrada de menú que previamente se seleccionó. Pero la función anterior hace referencias a elementos de la página, referencias que no existirán hasta que la página se haya cargado completamente. Por ello es necesario incluir la función en ese lugar, que ejecutará el resaltado del menu adecuado para cada página. Por ejemplo, en la página 1 que tiene un submenú pondríamos onload="muestraMenu(document.getElementById('menu1'), true);, es decir, cambiando menu0 por menu1, asi como true porqué esa página tiene un submenú. Y esto es todo lo que habría que modificar de una página a otra, aparte por supuesto de títulos y contenidos.

Resultado:
Ver página de resultado en index.html

Ejemplo: Botones con scripts. Usando evento onload con manejadores de eventos semánticos y funciones anónimas.

Donde se expone el evento onblur expusimos un ejemplo para dotar de botones personalizados a una página. Allí se dijo que un exceso de botones configurados de esta forma cargarían en exceso de código script. Una forma de "limpiar" de codigo una página es con el uso de las funciones anónimas y manejadores de eventos semánticos

Manejadores de eventos semánticos

Si no queremos incluir el código en el atributo para un determinado evento de un cierto elemento, entonces podemos incluir la sentencia siguiente para que se ejecute con la carga de la página:

referencia_al_elemento.on_evento = nombre_funcion_sin_argumentos
            

Por ejemplo, sea un elemento como <p id="pr" onclick="miFuncion()">, donde en el script de la cabecera de la página o en archivo externo se codificaría miFuncion(). Entonces si con la carga de la página podemos ejecutar document.getElementById("pr").onclick = miFuncion, ya no hace falta incluir el código en el elemento, quedando simplemente como <p id="pr">, pues cuando el usuario haga "click" sobre ese párrafo, ya tiene adjudicado un código para ese evento. Veáse que el nombre del evento debe ponerse con el prefijo on y además en la parte derecha sólo debe ponerse el nombre de la función, sin argumentos.

La utilidad es obvia, pues al inicio con la carga de la página se adjudicarían todas las funciones a los eventos que tengan los elementos y en la página no se encontraría ninguna línea de código script. Sin embargo no pueden, como es lógico, pasarse argumentos particulares, aunque esta técnica si tiene algunas ventajas. Una de ellas es que, de forma automática, se pasa un argumento con la referencia al objeto donde se causó el evento. Así desde miFuncion() podemos referirnos a ese elemento con this. Hay que tener en cuenta que en una función de usuario sin aplicar esta técnica, la referencia this apunta a la propia función, no al elemento que causó el evento. En ese caso la referencia al elemento se obtiene de otra forma, por ejemplo con document.getElementById().

Otro argumento que se pasa de forma automática es event, simplemente pasando cualquier nombre de argumento, luego puede ser referenciado el manejador event dentro de la función (no con Explorer, que tendremos que usar window.event como veremos más abajo).

Funciones anónimas

Para completar los eventos semánticos, es necesario que las adjudicaciones de eventos se realice cuando la página se haya cargado completamente. Esto es lógico pues debe accederse al elemento para adjudicarle el evento. Para realizar esto se puede usar una función anónima, que sin entrar en más detalles se codificaría así:

window.onload = function(){ 
    //adjudicación de eventos
    ...
    document.getElementById("identificador").on_evento = función 
    ...
}
            

Nuevamente evento y función se refieren al nombre de evento con on y al nombre de la función sin argumentos. Así no es necesario incluir ningún código tampoco para el evento onload en el elemento <body>. En resumen, es posible incluir todo el código script de una página en un archivo externo, sólo con incluir un script en la cabecera de la página que vincule con ese archivo. Esto da como resultado una página "limpia", siguiendo el mismo criterio que con CSS, pues en definitiva una página podría tener sólo código XHTML, con CSS y scripts en archivos externos vinculados en los correspondientes elementos de la cabecera.

Aplicando lo anterior a nuestro ejemplos de botones con scripts

El script para nuestro ejemplo contendrá todo el código necesario para manejar los botones tal como se muestra a continuación:

//Función de adjudicación de eventos
window.onload = function() {
    var botones = document.getElementById("botonera")
    var botonA = botones.getElementsByTagName("a")
    var botonImg = botones.getElementsByTagName("img")
    if (botonA.length != botonImg.length) {
        //error, los dos deben ser iguales
    } else {
        for (var i=0; i<botonA.length; i++) {
            botonA[i].onfocus = manejarBoton
            botonA[i].onblur = manejarBoton
        }
        for (var i=0; i<botonImg.length; i++) {
            botonImg[i].onmouseover = manejarBoton
            botonImg[i].onmouseout = manejarBoton
        }                    
    }
}        
//Función para manejar el resaltado de los botones
function manejarBoton (eventoEntrante){
    var evento = eventoEntrante || window.event
    switch (evento.type) {
        case 'mouseover':
            this.style.backgroundImage = "url(resalte.gif)"
            break
        case 'mouseout':
            this.style.backgroundImage = "url(fondo.gif)"
            break
        case 'focus':
            document.getElementById(this.id + "img").style.backgroundImage="url(resalte.gif)"
            break;
        case 'blur':
            document.getElementById(this.id + "img").style.backgroundImage="url(fondo.gif)"
            break;                        
    }
}
            

Encontramos dos funciones. La primera es la función que adjudica los eventos y que se ejecuta cuando la página haya completado su carga. Para iterar por los botones, hemos incluido estos dentro de un bloque <div id="botonera">. Así con var botones = document.getElementById("botonera") obtenemos una referencia. Luego podemos extraer un array para todos los elementos hijos de la botonera con var botonA = botones.getElementsByTagName("a") para los vínculos y otro para var botonImg = botones.getElementsByTagName("img"). Recuerde que cada botón se componía de un vínculo con imagen en su interior. Luego sólo resta recorrer sendos arrays y adjudicar los eventos oportunos, los cuales se adjudican a la función manejarBoton que enciende y apaga un botón.

La función que maneja los botones recibe dos argumentos de forma automática: this y event. El primero es una referencia al elemento que causó el evento. El segundo es el propio objeto evento que hay que pasar como un argumento con cualquier nombre. Le hemos dado el nombre eventoEntrante pero podría servir cualquiera.

Para que esto funcione con Explorer es necesario un paso intermedio con var evento = eventoEntrante || window.event que seleccione entre ese evento de entrada o la opción de Explorer de ofrecer el evento a través del objeto window. Luego podemos acceder al tipo de evento con evento.type. Según el tipo ejecutamos una u otra cosa, pues partiendo de que cada botón es un vínculo que contiene una imagen (<a><img .../></a>) y dado que el vínculo controla los eventos onfocus, onblur y la imagen controla onmouseover, onmouseout, sucederá lo siguiente:

  • Si el tipo es onmouseover, onmouseout es que el ratón entró o salió de la imagen, con lo que aplicamos uno u otro fondo backgroundImage al elemento imagen usando la referencia this.
  • Si el tipo es onfocus, onblur es que el vínculo obtuvo o perdió el foco, con lo cual dado que el id de una imagen la hemos conformado con id del vínculo añadiendo la cadena "img", entonces podemos acceder a la imagen para modificar también su fondo igual que antes.

Con esto el XHTML queda limpio de código script, el cual puede compararse con el del ejemplo citado sin usar esta técnica de ocultación de script.

<div id="botonera">

    <!--Primer botón-->
    <a id="bot1" href="pyramid.gif"><img class="bot" id="bot1img" width="32" height="32"
    src="pyramid.gif" alt="" title="Imagen 'pyramid.gif'" /></a>
    
    <!--Segundo botón-->
    <a id="bot2" href="tubo.gif"><img class="bot" id="bot2img" width="32" height="32"
    src="tubo.gif" alt="" title="Imagen 'tubo.gif'" /></a>
    
    <!--Tercer botón-->
    <a id="bot3" href="flecha.gif"><img class="bot" id="bot3img" width="32" height="32"
    src="flecha.gif" alt="" title="Imagen 'flecha.gif'" /></a>
    
</div>                
            
Resultado:
Puede ver la página de resultado en boton-script-2.html. El estilo se ha aplicado externamente en el archivo boton-script-2.css. El código script también se ha aplicado externamente en el archivo boton-script-2.js. Compruebe que entonces la página no tiene nada sobre estilo ni script viendo su código HTML "limpio". Puede compararlo con el código del ejemplo anterior que contenía script y estilo en su interior.

Ejemplo: Uso del evento onload. Aplicaciones con JavaScript: Calculadora

Quizás JavaScript no es el lenguaje más adecuado para aplicaciones ejecutables complejas. Sin embargo el hecho de que se ejecuten en navegadores puede ser una facilidad en el sentido de que no hay que distribuir las aplicaciones. Después de todo una aplicación en sentido general no es otra cosa que una interfaz de usuario y unos eventos que recogen las acciones del usuario y ejecutan algo. Usando controles de formularios en una página web podemos asegurar la interfaz con cualquier navegador, mientras que JavaScript proporcionará el mecanismo de ejecución con los eventos.

En este ejemplo proponemos una aplicación simple de una Calculadora. Su utilidad es más bien escasa, pero nos proporcionará la experiencia y nos dirá hasta donde podemos llegar con JavaScript. Para ello disponemos de una página con controles del tipo <input> para conformar los botones y la pantalla de nuestra calculadora. Estos controles no se incluirán en un elemento <form>, pues no se trata de ningún formulario que se haya de enviar.

Combinando las propiedades adecuadas de los elementos y el JavaScript, podemos configurar lo necesario para que esta calculadora funcione. Se trata de seguir básicamente lo que se expuso en un ejemplo anterior sobre la adjudicación de eventos de los elementos. Veáse el código de la página, estilo y JavaScript externos.

Resultado:
La calculadora se encuentra en la página calc.html. También hemos hecho una versión con todo lo externo incluido en la página HTML, con objeto de poder usarla en otro contexto sin necesidad de llevar archivos de estilo o de script externos. Puede abrirla en una nueva ventana normal con calculadora.html, o bien puede usar el siguiente botón con un script que la abre en una ventana emergente con las dimensiones ajustadas al tamaño de la calculadora:
(2010) Ampliaciones de la calculadora.

Esta aplicación de la calculadora fue una de las primeras que hice para aprender JavaScript. A medida que voy avanzando en esta materia he ido utilizando esta aplicación para adaptarla a otros conceptos. Esta nota es para relacionar las posibilidades realizadas hasta el momento con esta aplicación calculadora:

  1. (2008) Calculadora básica con calc.html que usa los archivos externos calc.js y el estilo de calc.css. Aquí puede ver los codigos del HTML, js y CSS.
  2. (2008) Calculadora integrada en el documento con calculadora.html que integra el script y los estilos en el mismo documento. Es exactamente como la anterior pero no usa los archivos externos. sino que los integra en elementos <script> y <style> de la cabecera <head> del documento. En el código fuente de la página encontrará todo el código.
  3. (2010) Calculadora con html dinámico usando el script externo calculadora.js y el estilo calculadora.css, donde el código HTML de los botones y otros elementos se declara como un string literal para ser insertado con innerHTML o de otra forma equivalente en un documento. Puede ver el codigo con más comentarios. Este ejemplo no se usa en este glosario, pero lo implemento ahora en este ejemplo calculadora-html-dinamico.html para que pueda observarlo.
  4. (2010) Objeto JavaScript para una calculadora. En este año he estado aprendiendo sobre los objetos de JavaScript y he reconvertido la calculadora anterior, que actuaba con funciones, en un objeto de JavaScript. Esto nos permite abrir varias calculadoras independientes en el mismo documento. Se implanta con archivos externos calculadora-objeto.js para el script y calculadora-objeto.css para el estilo. Puede ver el codigo del objeto con más comentarios. Hay ejemplos en los temas de cómo se hace, en el apartado formulario emergente para una calculadora, donde insertamos un objeto calculadora dentro de un objeto mensaje emergente.

Evento cuando la página se descarga <E onunload = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando un página se descarga. Sólo puede incluirse en el elemento <body>.

Evento cuando se remite un formulario <E onsubmit = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se remite un formulario. Sólo puede incluirse en el elemento <form>.

Ejemplo: Uso del evento onsubmit. Formas de acceder a un elemento formulario con JavaScript. Validación para el envío de formularios.

Una de las utilidades de los scripts es realizar un control sobre los datos que introduce el usuario en los controles de un formulario. Para ello es necesario acceder al formulario y a sus elementos. Con JavaScript podemos obtener estas referencias de varias maneras entre las cuales exponemos las siguientes:

  • Con document.forms[i].elements[j]. El objeto documento dispone de un array con las referencias de todos los formularios que contiene. Cada formulario a su vez tiene otro array con todos sus elementos. Los índices como siempre con JavaScript comienzan desde cero. El único problema es que el array se rellena con el orden según aparición de cada formulario en la página o de cada control dentro de un formulario, por lo que si luego se cambian de orden también habrá que reubicar el código relacionado.
  • Con document.nombre_formulario.nombre_elemento, donde nombre_formulario y nombre_elemento son los valores de los atributos name dados a un formulario y elemento respectivamente. De esta forma evitamos el problema anterior sobre el ordenamiento.
  • Con document.getElementById("identificador"), donde identificador es el valor del atributo id del formulario o de un elemento.
  • Se puede acceder a todos los elementos del mismo tipo de un formulario usando nombre_formulario.getElementsByTagName("tag") donde tag es uno de los tipos input, button, textarea etc.

Una vez que obtengamos una referencia a un elemento de formulario, podemos usar sus propiedades como:

  • Saber con type el tipo de elemento. Por ejemplo, para un elemento <input> nos interesaría saber si es un text, password, checkbox, ....
  • Obtener una referencia al formulario que lo contiene con form. Por ejemplo, para obtener la referencia a su formulario de un botón de una página con identificador determinado haríamos document.getElementById("identif").form
  • Acceder a su valor con value para leerlo o modificarlo, que en definitiva es realizar el control sobre los datos que introduce el usuario.

En la exposición de otros eventos ya se han desarrollado algunos ejemplos relacionados con formularios, de los cuáles podemos destacar por su interés los siguientes:

  1. Ejemplo para validar números en un cuadro de texto con el evento onkeypress.
  2. Ejemplo para limitar número de caracteres en un cuadro de texto multilinea con el evento onkeypress.
  3. Ejemplo para dirigir el foco a los controles de un formulario, con el uso del evento onfocus.
  4. Ejemplo para controlar texto con el uso del evento onkeyup.

Pero los eventos propios que sólo se aplican a elementos de formulario son <E onsubmit>, <E onreset>, <E onselect> y <E onchange>. En algunos ejemplos señalados en el párrafo anterior se realizaban algunas comprobaciones sobre los datos de texto que introducía el usuario, de tal forma que se controlaba carácter a carácter la validez del campo. Esto será necesario cuando no queremos que se introduzcan ciertos caracteres o limitar el número de ellos mientras el usuario está rellenando los campos. Pero para una validación general de un formulario quizás es más práctico realizar una validación completa previa al envío. Este ejemplo a continuación tiene ese propósito.

Por un lado tenemos un formulario simple compuesto sólo por campos de texto de los cuáles cuatro deberán ser rellenados obligatoriamente por el usuario y cinco de ellos serán validados:

<form name="formvalidado" action="formval.php"  (o "formval.jsp" para JSP)
    method="post" onsubmit="return validaForm(this)">
    <label>Nombre (*):
        <input type="text" name="nombre" size="50" maxlength="50" 
        title="Valor requerido" />
    </label><br />
    <label>Domicilio:
        <input type="text" name="domicilio" size="100" maxlength="100"
        title="Valor opcional" />
    </label><br />
    <label>D.N.I.(*):
        <input type="text" name="dni" size="9" maxlength="9" 
        title="D.N.I. requerido" />
    </label><br />
    <label>Teléfono 1(*):
        <input type="text" name="telefono-1" size="9" maxlength="9" 
        title="Teléfono requerido" />
    </label><br />
    <label>Teléfono 2:
        <input type="text" name="telefono-2" size="9" maxlength="9" 
        title="Teléfono opcional" />
    </label><br />                  
    <label>E-mail (*):
        <input type="text" name="e-mail" size="100" maxlength="100" 
        title="E-mail requerido" />
    </label><br />
    <div id="pie" style="font: 0.8em 'Arial';">Los campos con (*) son requeridos</div>       
    <input type="submit" name="envio" value="Enviar" />
    <input type="reset" value="Borrar" />
</form>                  
            

La validación se producirá cuando la función validaForm(this) devuelva true o false. Con un valor true el formulario enviará los datos al servidor, mientras que esta acción será abortada si la función devuelve false.

Puede ver el código del HTML y javascript en codigos.html. El script tiene utilidad para cualquier formulario siempre que se observen las siguientes reglas:

  • Todos los controles <input> de tipo text del formulario serán objeto de validación.
  • El atributo name de ese control debe ser comprensivo de la descripción del campo, pues se usará para dar mensajes al usuario sobre que campo se ha detectado un error.
  • Estos controles deben llevar obligatoriamente un atributo title para que el script pueda seleccionar el tipo de validación que realizará. El contenido de este título será de 2 palabras exactamente, siendo la segunda "requerido" u "opcional". La primera puede ser "Valor" o bien alguna de las siguientes:
    • "D.N.I."
    • "Teléfono"
    • "E-mail"

Los que contengan como primera palabra "Valor" no serán validados aunque serán requeridos si contiene la segunda palabra "Requerido". Los que no contengan "Valor" como primera palabra si se validará la corrección de sus datos siempre que sea "requerido" o que sea "opcional" y el campo tenga algún contenido.

Puede agregar más tipos de validaciones en el script en el lugar correspondiente (en el switch de la función validaTextoInput()). No se tiene en cuenta el uso de mayúsculas ni la codificación de caracteres, sólo que ha de tener exactamente 2 palabras separadas por un espacio. Es decir, se realizará una división de la cadena del título por el carácter espacio con la función split() de Javascript. Se debe observar que el título lo verá el usuario, por lo que la primera palabra en combinación con la segunda le indicará que requerimientos de datos ha de introducir en ese <input>. Veámos las posibles combinaciones del título:

  • "Valor opcional" para un campo que no es requerido (puede estar vacío)
  • "Valor requerido" para un campo que se requiere con contenido, aunque no se valida el mismo.
  • "D.N.I. opcional" para un campo que puede estar vacío, pero si contiene algo se validará si es un D.N.I. correcto.
  • "D.N.I. requerido" para un campo que es requerido y que se validará si contiene un D.N.I. correcto.
  • Etcétera...

Si el formulario es correcto se desactiva el botón de envío para impedir envíos duplicados. Esto se puede producir por la lentitud de la conexión por ejemplo, por lo que durante la espera la página pudiera no mostrar signos de actividad y el usuario estuviera tentado de volver a pulsar el botón de envío, pudiendo duplicar el envío de datos. De hecho hemos añadido un alert(mensaje) para comprobar el efecto de una espera en el envío, pues usando un servidor local o una conexión rápida no habrá prácticamente tiempo de observar los efectos en pantalla cuando el resultado sea correcto. Este mensaje emergente no se incluiría en una versión definitiva del formulario.

Resultado:

Este formulario es enviado a un servidor, pero la validación se realiza en el navegador del usuario, con lo que independientemente de la recepción de datos por el servidor, el navegador podrá validar y enviar el formulario o no enviarlo si hay algo que no es correcto. Para comprobar el script hemos dispuesto que antes del envío al servidor salga un mensaje para detener la ejecución y observar el efecto, aunque este mensaje debería quitarse en una situación real.

Evento cuando se reinicia un formulario <E onreset = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se reinicia un formulario. Sólo puede incluirse en el elemento <form>.

Evento cuando se selecciona texto en un control <E onselect = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se reinicia un formulario. Sólo puede incluirse en el elemento <form>.

Evento cuando se cambia el valor de un control <E onchange = "x">

Valor del tipo %Script para incluir el codigo script que debe ejecutarse cuando se reinicia un formulario. Sólo puede incluirse en el elemento <form>.