Documentos de Académico
Documentos de Profesional
Documentos de Cultura
etc., que aparecen en este libro son rnarcas registradas de sus respectivas
compafiias u organizaciones.
Prefacio 21
Introduccion 25
Ventajas de JavaScript 25
25
.............. ................. 26
Reducci6n de la carga del servidor ................................................. 26
JavaScript esta creciendo .. ......................................................... 26
Es posible que no quede otra alternativa .......... 27
Pero aGn hay mas ......................................................................... 27
Estrategia para la programaci6n en JavaScript 27
Propiedades de la aplicaci6n ........................................................... 28
Audiencia ........... .............. 28
iC6mo puedo salvar todos estos obstaculos? .......................,......... 29
Exploradores cruzados ............................................................. 30
Una pequeiia degradacih o cambio en la efectividad ................ 30
Apuntar bajo ............................................................................ 30
8 Contenidos
i
Contenidos 9
2 Examen online 69
5 ImageMachine 159
Requisitos para la ejecuci6n .......................................... 162
Analisis de la sintaxis ................................................................. 163
Paso 1: carga de paginas ... ............... .................... 174
Paso 2: introducir 10s valores predeterminados y 10s pares
de imiigenes ............................................. 175
Paso 3: completar la ruta de las imagenes, 10s atributos HREF,
etc. ... .......................................... ............ ................. 176
captureDefaultProfile() ....... ............................. 176
generateEntryForm0 ................................................................ 178
genJavaScript() ................... ...... ............ ........ 181
. .
La hora de las decisiones ........................................................... 184
Generar el c6digo ................................................. 185
Paso 4: seleccionar ((Preview))para ver el codigo en acci6n ............. 186
Paso 5: seleccionar ((ChangeInfo))para hacer cambios ................... 186
Posibles ampliaciones: afiadir atributos a la plantilla ............. 187
Paso 1: agregar campos ............ ... ... ... ... ............ ...... ... .............. ...... 188
Paso 2: crear arrays con setArrays().......................... 188
Paso 3 : capturar 10s nuevos valores predeterminados .. ...... ............ 189
Paso 4: agregar campos de texto en generateEntryForm0 .............. 189
Paso 5: referenciar y asignar 10s nuevos valores en
genJavaScript0 ............. .................... ... ... ...... ... ... ................ 190
Paso 6: generar HTML adicional en genJavaScript0 190
..
Version necesaria ...................................................................... 194
Funciones ................................................................................. 194
. .
cookies .js ............................... .................................... 198
Us0 prhctico ............................................................................. 198
Versidn necesaria ...................................................................... 199
Funciones ................................................................................. 199
dhtml.js ..................... ......................................... 202
Us0 practico ............................................................................. 202
..
Version necesaria ...................................................................... 202
Funciones ................................................ ...................... 202
events.js ................................................. ................................. 204
Us0 prhctico ............................................................................. 204
..
Version necesaria ...................................................................... 204
Funciones ..................................................... .......... 204
frames.js ............................................................................................ 210
Us0 prhctico ............................................................................. 210
Versidn necesaria ...................................... ............................ 210
Funciones ............. ..................... ..... 210
images.js ........................................................................................... 213
. .
Us0 practico ............................................................................. 213
Version necesaria ........ 213
Funciones ........ ................................... 213
navbar.js ............................................................................................ 214
Us0 prActico ............................................................................. 214
Version necesaria ....... ............... 214
Funciones ....... ............................................................... 214
numbers .js ........................................................................................ 216
Us0 prActico ............................................................................. 216
Version necesaria ..... ......... ... 216
Funciones ................................................................................. 216
objects.js ............................................................................................ 218
Us0 practico ............................................ ........................ 218
Versidn necesaria ................................. 218
Funciones ................................................................................. 218
strings.js ............................................................................................ 223
Contenidos 13
2 78
Analisis de la sintaxis ................................. 2 79
........................................ 28 1
Miembros de alto nivel 282
285
Propiedades del producto .................. .............................. 290
291
Crear productos y categorias ............................... 293
Crear la bolsa de la compra ........................ ..................... 29.5
Paso 2: mostrar 10s productos .......... .............................. 296
manager.htm1 ........... 298
306
..................... 308
.............................. 309
31 1
Paso 3: mostrar todas las categorias .............................. 312
..................... 313
iD6nde est6 el c6digo DHTML? .............................. 313
314
Buscar por productos ............ ................................... 316
31 7
Buscar en la base de datos ya existente .......................................... 318
Navegaci6n por categorias/productos ...,.......... .................. 319
El c6digo del vinculo ....................................... 32 3
Paso 5 : cambiar el ordenhegistro ............... ..................... 322
325
Guardar el registro de la factura ......................................... 328
Ajustar showBag( ): mostrar 10s totales ......... 330
((CheckOut)) .................................... .............................. 33 1
Completar la pantalla 334
334
((ResetQt y s ...... .... ...................................... ...
)) 334
((ChangeBag)) ............................. .............................. 335
Las funciones olvidadas ................................................. 336
336
Contenidos 15
Epflogo 43 1
B Web Resources 49 7
49 7
Referencia a JavaScript ................................... ..................... 498
Preguntas y respuestas sobre JavaScript . ............................ 499
DHTML Reference ............................. ................................ 499
Document Object Model Reference ......................................... 500
Perl/CGI Reference ............ ........................................ 500
Graphics Resources ...... ........................................... 500
Aplicaciones similares ......................................... 501
Motores de busqueda para el cliente ......................... 501
ExAmenes online .......................................... 501
.................. 502
Interfaces para motores de busqueda multiples ............................. 503
Generador de secuencias ..................... ............................ 503
Bibliotecas .......................... ......... ................................. 504
Cookies ........... ...................... ......................................... 505
Carros de la compra ......... .......................................... 505
Encriptadores ............. ........................................... 506
Concepto ccarrastrar y soltar)) ... ........................ .......... 507
Ayuda contextual ......................................... 508
Analisis de la sintaxis
Cuando terminemos de jugar con la aplicacion y queramos saber quC c6digo es
el responsable de tales acciones, acudiremos aqui. En esta seccion se hablara del
codigo, normalmente, analizandolo linea a linea. Es la seccion mas larga del capi-
tulo, asi que nos tendremos que poner comodos antes de adentrarnos en ella.
Tecnicas de JavaScript
Segun avancemos en el analisis del codigo, habra una serie de puntos en 10s
que deberemos detenernos y destacar alguna ttcnica que merece la pena recordar.
Prefacio 23
Posibles ampliaciones
En esta seccion veremos las posibilidades que hay para ampliar el codigo. Hay
veces en que hare alguna sugerencia y otras en las que incluso ofrecere codigo
hecho por mi. Otras, sefialark una direccion de Internet a traves de la que se pue-
de bajar otra version de codigo, mas ejemplos, etc. En cualquier caso, le aseguro
que con 10s ejemplos que veremos en la obra no se detendra ni un instante a pre-
guntarse "Bien, icomo se supone que voy a colocar esto en mis paginas Web?"
El codigo
El libro esta lleno de aplicaciones. No se sorprenda. Va a ver mucho codigo. Al-
gunas aplicaciones contienen varios cientos de lineas y ocupan varias paginas.
' En otros casos, Vera que el c6digo se repite mucho y es que prefiero que sea asi
a que tenga que estar pasando paginas hacia delante y hacia atras hasta que lo-
calice la seccion de la que se esta hablando.
Uno de 10s inconvenientes que tiene escribir el codigo en el libro es precisamen-
te ese, que esta en el libro. Tenemos que adaptarnos a las liniitaciones fisicas de
la pagina. Esta tiene un ancho determinado, por lo que habra ocasiones en las
que el codigo saltara automaticamente a la siguiente linea. Para mejorar la le-
gibilidad del codigo, lo he llenado de comentarios. La verdad es que 10s chicos de
maquetacion han hecho un gran trabajo a1 adaptar el formato del codigo a las
limitaciones de las paginas. Per0 aun sigue habiendo ocasiones en las que resul-
ta mas sencillo mirar el codigo a traves de la pantalla de u n editor.
Desarrollo y pruebas
Sin mas particular, he mostrado el hardware y el software que he usado para
desarrollar el c6digo de este libro. He verificado el material en un entorno Windows,
asi que quiza 10s usuarios de Unix o Macintosh encuentren algun problema.
Hardware: IBM ThinkPad 55/P75/16M Compaq Presario/P233/1OOM, IBM
Aptiva C23/P120/129M, Dell Optiplex/P2-266/128M, Sun SPARC 20.
Sistemas operativos: Win95, WinNT Workstation 4.0, WinNT Server 4.0 y So-
laris 2.5.
Exploradores Web: Netscape Navigator 3.0, 3.04 Gold, 4.0, 4.04, 4.07, 4.08,
4.5; Microsoft InternetExplorer 3.0, 3.02, 4.0, 4.01, 5.00.
Resoluciones: 640x480, 800x600, 1024x768, 1152x900, 1280~1024.
Obviamente, no he probado todas las aplicaciones con estas condiciones. Pero
he intentado que el c6digo fuese lo suficientemente robusto como para que fun-
cionase con la mayoria de ellas.
Introduccion
/-
Ventajas de JavaScript
Ninguno de 10s lenguajes de programacion del mercado se puede considerar
como el mas adecuado para la creacion de aplicaciones. Cada uno tiene sus ven-
tajas e inconvenientes. Los ultimos avances en JavaScript y la proliferation de
tecnologias como DHTML, Java y Macromedia Flash, han colocado a JavaScript
en una posicion ventajosa para aprovechar estas herramientas en la creacion de
grandes soluciones para la Web. A continuacion mostramos algunas razones
apoyando el us0 de JavaScript para crear aplicaciones:
Usabilidad
JavaScript es, con diferencia, el lenguaje de programacion que mas se utiliza
en la Web. Hay publicadas millones de paginas Web que incorporan elementos
que lo usan. La mayoria de 10s exploradores Web pueden trabajar con 61 (aunque
en el caso de Microsoft estemos hablando de JScript). Y tanto Microsoft como
Netscape siguen investigando otras formas de sacar mas provecho a este len-
guaje. Gracias a estos factores podemos asegurar que la mayoria de 10s usua-
rios de Internet podran trabajar con JavaScript.
JavaScriptesta creciendo
Cuando JavaScript salio a la luz, se provoc6 un gran revuelo en la comunidad
informatica debido fundamentalmente a la aparici6n de 10s objetos Imagen y de
lntroduccion 27
I
Propiedades de la aplicacion
En primer lugar, i q u t va a realizar la aplicacion?Tenemos que ser muy preci-
sos. iQue no ofrecera la aplicacibn? Supongamos que queremos desarrollar un
formulario HTML para enviar un mensaje de correo electronico. Tendremos que
considerar las siguientes cuestiones:
Audiencia
Es muy importante identificar quiCn va a utilizar la informacibn, puesto que
de esta forma podremos determinar las propiedades de la aplicacion. Hemos de
establecer unas respuestas muy concretas a las siguientes preguntas:
iQu6 exploradores Web utilizaran nuestros visitantes? iQut versiones:
2.x, 3.x, 4.x o superior?
iSe va a utilizar la aplicacion a travLs de Internet, de una intranet o local-
mente en ordenadores individuales?
iPodemos determinar la resolucion del monitor que tendran 10s usuarios?
iQuC tipo de conexiones tendran 10s usuarios? iUn mbdem de 56k? iUna
linea RDSI? iUna ADSL?
Es posible que a1 principio pensemos que estas preguntas no tienen nada que
ver con JavaScript. El tipo de conexibn, ipero quC mas da? No vamos a tener
que configurar un router ni nada por el estilo. Ni tenemos que contar con el cer-
tificado de Cisco. En cualquier caso, vamos a contestar una por una estas pre-
guntas y veremos que importancia tiene cada una de ellas.
El tema del explorador Web es muy interesante. Generalmente, si es muy re-
ciente podremos utilizar las ultimas versiones de JavaScript. Por ejemplo, si la
audiencia trabaja con NN 2.x y con MSIE 3.x (aunque no veo por que iban a ser
lntroduccion 29
asi las cosas), podemos automatizar el giro de las imagenes. Las versiones de
JavaScript y JScript de estos servidores no pueden trabajar con 10s objetos Ima-
gen o documento.imagen.
Como la mayoria de la gente ha actualizado la version de su explorador a 4.x,
tambitn podran trabajar con el giro de imagenes y con 10s objetos mencionados.
Es decir, que podemos hacer que nuestras versiones se ejecuten en mas de u n
tip0 de explorador Web o bien centrarnos para una version especifica.
iDonde se encuentra la aplicacion? iEn Internet, en una intranet o en el orde-
nador de alguien que lo haya convertido en una especie de kiosco? La respuesta
a esta pregunta nos darh una serie de pistas muy interesantes. Por ejemplo, si la
aplicacion se encontrara en Internet podremos estar seguros de que la gente
utilizara casi cualquier tip0 de explorador que podamos imaginar para llegar a
ella. Si la aplicacion esta restringida a una intranet o a una mhquina local, las
opciones se reducen. Es posible que casi todos 10s usuarios utilicen el mismo ex-
plorador Web. Durante la creacion de este libro, trabajt de consultor para una
filial de Microsoft. Si mis aplicaciones no funcionan en Netscape Navigator, la
verdad es que no importa, porque todos 10s usuarios trabajaran con MSIE.
Otro tema a tener en cuenta es la resolucion del monitor. Podemos incluir una
tabla de 900 pixeles de ancho y si 10s usuarios que acceden a ella unicamente
trabajan con una resolucion de 800x600 se perderan parte de 10s datos. Pero,
ipodemos establecer una resolucion fija para todos 10s usuarios? Si la aplicacion
se publicara en Internet, la respuesta es no. Per0 si vamos a trabajar a travts de
una intranet, es posible que tengamos algo mas de suerte. Algunas empresas
estandarizan el hardware, software, exploradores, monitores, e incluso tambitn,
resoluciones.
El tipo de conexion tambitn tiene su efecto sobre la aplicacion. Supongamos
que vamos a crear una animacion en la que se ven escenas correspondientes a la
ultima pelicula de Steven Spielberg. Bien, la mayor parte de 10s usuarios que se
conecten con un modem estandar de 56K posiblemente vean antes la pelicula en
el cine que el trailer en la pagina Web porque tarde demasiado tiempo en cargar-
se el cbdigo. Hay que tener en cuenta el ancho de banda a la hora de crear una
aplicacion.
Exploradores cruzados
Este mCtodo igualitario basado en "lo mejor para todos" se basa en la utilizacion
de codigo comun que puedan comprender la mayoria de 10s exploradores Web.
Cuando hablo de la mayoria de 10s exploradores, me estoy refiriendo a1 MSIE 4.x
y a NN 4.x. Si hacemos que nuestra aplicacion utilice propiedades que compren-
dan ambos exploradores Web nos estaremos asegurando que la mayoria de 10s
usuarios la podran ejecutar sin ningun problema.
Apuntar bajo
Este sistema da por sentado que todos 10s usuarios tienen un explorador NN
2.0, que trabajan con pantallas de 640x480, modems de 14.4K y su equipo es
un Pentium a 33 MHz. Las malas noticias seran que no podran utilizar ningun
c6digo de JavaScript 1 .O. Ninguna animacion, ni capas, ni expresiones regula-
res, ni tecnologias externas (eso si, por lo menos podemos utilizar cuadros). Las
buenas noticias son que la gran mayoria de la poblacion de Internet podra
utilizar la aplicacion. En realidad, 10s ultimos cambios que se han efectuado a
JavaScript no permiten afirmarlo con total seguridad. La verdad es que tengo
que admitir que he apuntado realmente bajo, per0 no es muy extraiio encon-
trarse con que gran parte de 10s navegantes de la Web trabajan con las versiones
3.x de NN y MSIE. Esta forma de trabajar, tambikn tiene sus ventajas.
Apuntar alto
Si 10s usuarios no tienen MSIE 5 .O, podremos asumir que no saben lo suficien-
te de informtitica como para utilizar nuestra aplicacion, por lo que 10s daremos
de lado. Nos pondremos a codificar, disponiendo de acceso a1 modelo de docu-
mentos de MSIE, el modelo de eventos, la construccion de datos, etc. Obviamen-
te, a1 rFchazar a una gran parte de la audiencia, nos aseguramos que la aplicacion
tardara mas tiempo en quedarse obsoleta.
pero nos podemos encontrar con un problema. Volvamos a1 tema del tipo de
conexion. Como no suele ser posible determinar el tip0 de conexion que utiliza-
ran 10s usuarios, podemos hacer que Sean ellos 10s que escojan el tipo de aplica-
cion que desean ejecutar. Por medio de un par de vinculos, podemos hacer que
aquellos que dispongan de una conexion rapida, carguen 10s efectos mas espec-
taculares, mientras que el resto podra acceder a una version reducida de la mis-
ma aplicacion.
guardar una parte del codigo dentro de u n archivo y utilizarlo por medio de
este tip0 de llamadas. Merece la pena utilizar archivos de codigo con JavaScript.
De hecho, uno de 10s capitulos esta dedicado a ello.
Algunas aplicaciones contienen codigo que simplemente se ha copiado de un
punto y pegado en otro. Este tipo de codigo es el que se podria usar en 10s archi-
vos de 10s que hablamos, per0 he utilizado este otro sistema porque este es un
libro que trata de ensefiar, no de marear a1 lector con referencias a c6digo que se
encuentra en otro lugar de donde deberia aparecer. De esta forma, el codigo
siempre estara delante cuando se le necesite y se evita tener que estar retroce-
diendo constantemente a otros puntos del libro. Una vez que se compruebe que
la aplicacion funciona correctamente, merecera la pena plantearse la creacion
de archivos de codigo.
Aislar JavaScript
Siempre que sea posible, ajustaremos el contenido de nuestra aplicacidn a las
etiquetas <SCRIPT></SCRIPT> en vez de hacerlo a <HEAD></HEAD>.
inviable. Sin embargo lo utilizo siempre que puedo, porque mejora la organiza-
cion del scipt y las posibilidades de que las llamadas a las funciones sigan un
orden determinado.
Avanzar
Bien, con todos estos puntos ya nos hemos hecho una idea de la estructura que
tendran las aplicaciones en JavaScript. Per0 ha llegado la hora de empezar a
divertirse.
Capitulo 1 -
Motor de busqueda para el cliente
Todos 10s sitios Web pueden trabajar con un motor de busqueda pero, ipor qut
cargar a1 servidor con todas las consultas? El Motor de busqueda para el cliente
permite que 10s usuarios puedan buscar a traves de las paginas Web sin necesi-
tar para nada a1 servidor Web. En vez de enviar las peticiones a una base de
datos o a un servidor de aplicaciones, cada usuario descarga una base de datos
con las paginas Web solicitadas. Dicha base de datos no es otra cosa que un
array en JavaScript. Cada registro se guardara en un elemento del array.
Esta forma de trabajar tiene algunas ventajas, como por ejemplo la reduction
de la carga de trabajo del servidor y una mejora en el tiempo de respuesta. Asi de
sencillo. Hemos de recordar que las limitaciones de la aplicacion dependeran
unicamente de 10s recursos del sistema del usuario, sobre todo de la velocidad
del procesador y de la cantidad de memoria libre. En cualquier caso, puede
tratarse de una gran utilidad para u n sitio Web. En la figura 1.1 se puede ver la
primera pantalla de la interfaz.
La aplicacion cuenta con dos metodos booleanos de busqueda: AND y OR.
Podemos buscar 10s documentos a partir de su titulo y descripcion, o bien por el
URL. Su manejo es muy sencillo. Basta con introducir 10s ttrminos que se quie-
ren localizar y pulsar Intro. Este es el desglose de la opci6n de busqueda:
Cuando se introduzcan tkrminos separados por espacios, la aplicacion
mostrara todos 10s registros que contengan cualquiera de las palabras
deseadas (se utiliza el booleano OR).
+
Si se coloca un signo delante de la cadena de consulta, se obtendran 10s
registros en 10s que aparezcan todos 10s tkrminos especificados (booleano
AND).
36 Motor d e busqueda para el cliente
En la figura 1.2 tenemos 10s resultados que se han obtenido a1 desarrollar una
busqueda. Se ha utilizado el sistema predeterminado (sin prefijos) y el tkrmino
que se ha buscado ha sido javascript. Todas las busquedas generan sobre la
marcha una pagina de resultados donde se muestran 10s resultados de las ulti-
mas busquedos, seguida por un enlace a una pagina de ayuda.
Tambikn se pueden buscar documentos por su URL. La figura 1 . 3 nos muestra
una busqueda donde se ha utilizado el prefijo url: para indicarle a1 motor de
busqueda que unicamente ha de mostrar 10s documentos que tengan html en su
URL. Aunque tambikn se incluira la descripcion del documento, lo primero que
aparecera en la pantalla sera el URL (el localizador del documento). Este sistema
unicamente permite busquedas sencillas. Per0 no ha de preocuparnos, porque la
mayoria de 10s usuarios se contentaran con eso. N o hay mucha gente que uti-
lice algoritmos para complicar las opciones de la busqueda.
La aplicacion puede limitar el numero de resultados que mostrara por pagina
y crear botones para acceder a la pagina anterior o posterior a la de resultados.
De esta forma, se mejorara el aspect0 de la presentacion y el usuario no se
perdera entre tantos registros. El numero de documentos que apareceran por
pagina dependera de nosotros. Por defect0 se mostraran 10.
Motor de busqueda para el cliente 37
ena5uipr &@
Cbent-Side Search Engine
ud hfml
ClientSide Seuch Engine
Analisis de la sintaxis
Esta aplicacion se compone de tres archivos HTML (index.htrnZ, nav.htrnZ y
rnain.htrnZ) y de un archivo fuente en JavaScript (records.js).Los tres archivos
HTML incluyen una cabecera, donde se introducen 10s ttrminos que se quieren
buscar, una zona de trabajo y una pagina predeterminada con las instrucciones
de uso.
M o t o r de busqueda para el cliente 39
nav.htmI
El corazon de la aplicacion se encuentra dentro del archivo navhtrnl. De hecho,
ademas de este archivo, el unico sitio donde veremos algo de JavaScript sera en
las paginas de resultados que se crearan sobre la marcha. Vamos a echar un
vistazo a1 codigo. Lo tenemos en el ejemplo 1.1.
Ejemplo 1.1. Codigo fuente del archivo nav.htm1
1 <HTML>
2 <HEAD>
3 <TITLE>Search Nav Page</TITLE>
4
5 <SCRIPT LANGUAGE="JavaScriptl.1" SRC="records.js"></SCRIPT>
6 <SCRIPT LANGUAGE="JavaScriptl.I">
7 <!-
8
9 var SEARCHANY = 1;
10 var SEARCHALL = 2;
11 var SEARCHURL = 4;
12 var searchType = ";
13 var showMatches = 10;
14 var currentMatch = 0;
15 var copyArray ' = new Array ( ) ;
16 var docObj = parent.frames[ll.document;
17
1 8 function validate(entry) {
19 if (entry.charAt(0)== " + " ) {
20 entry = entry.substring(1,entry.length);
21 searchType = SEARCHALL;
22 I
23 else if (entry.substring(0,4)== "url:") {
24 entry = entry.substring(5,entry.length);
25 searchType = SEARCHURL;
26 I
27 else { searchType = SEARCHANY; I
28 while (entry.charAt(0) == ' ' ) {
29 entry = entry.substring(1,entry.length);
30 document.forms[O].query.value = entry;
31 I
32 while (entry.charAt(entry.length - 1) == ' {
33 entry = entry.substring(0,entry.length - 1);
34 document.forms[O].query.value = entry;
35 I
36 if (entry.length < 3 ) I
37 alert("You cannot search strings that small. Elaborate a
little.");
38 document. forms [ O 1 .query.focus ( ) ;
39 return;
40 I
40 Motor de busqueda para el cliente
41 convertString(entry);
42 }
43
44 function convertString(reentry) {
45 var searchArray = reentry.split( " " ) ;
46 if (searchType == (SEARCHANY I SEARCHALL)) {
requireAll(searchArray); 1
47 else ( allowAny(searchArray); }
48 1
49
50 function allowAny(t) (
51 var findings = new Array(0);
52 for (i = 0 ; i < profiles.length; i++) {
53 var compareElement = profiles[i].toUpperCase();
54 if(searchType == SEARCHANY) {
55 var refineElement = compareElement.substring(0,
56 compareElement.indexOf(' IHTTP'));
57 1
58 else (
59 var refineElement =
60 compareElement.substring(compareElement.index0f >IHTTP'),
61 compareElement.1ength);
62 1
63 for ( j = 0; j < t.length; j++) (
64 var comparestring = t[jl.toUpperCaseO;
65 if (refineElement.indexOf(compareString)! = -1)
66 findings[findings.lengthl = profiles[il;
67 break;
68 1
69 1
70 1
71 verifyManage(findings);
72 1
73
74 function requireAll(t) {
75 var findings = new Array();
76 for (i = 0; i < profiles.length; i++) I
71 var allconfirmation = true;
78 var allstring = profiles[il.toUpperCaseO;
79 var refineAllString = allString.substring(0,
80 allString.indexOf('IHTTP'));
81 for (j = 0; j < t.length; j + + ) (
82 var allElement = t[jl.toUpperCaseO;
83 if (refineAllString.indexOf(al1Element) == -1) {
84 allconfirmation = false;
85 continue;
86 1
87 1
88 if (allconfirmation) I
89 findings[findings.length] = profiles[il;
90 1
Motor de busqueda para el cliente 41
91 }
92 verifyManage(findings);
93
94
95 function verifyManage(resu1tSet) {
96 if (resultSet.length == 0) ( noMatch0; }
97 else {
98 copyArray = resultSet.sort0;
99 formatResults(copyArray, currentMatch, showMatches);
100 }
101 1
102
103 function noMatch0 {
104 docObj.open0;
105 docObj.writeln('<HTML><HEAD><TITLE>SearchResults</TITLE>
</HEAD> +
106 '<BODY BGCOLOR=WHITE TEXT=BLACK>' +
107 'ITABLE WIDTH=90% BORDER=O ALIGN=CENTER><TR><TD VALIGN=TOP>'+
108 '<FONTFACE=Arial><B><DL>' +
109 '<HR NOSHADE WIDTH=100%>"' + document.forms[01 .query.value +
110 "' returned no results.<HR NOSHADE WIDTH=100%>' +
111 '</TD></TR></TABLE></BODY></~TML>');
112 docObj .close0 ;
113 document.forms[Ol.query.selectO;
114 I
115
116 function formatResults(results, reference, offset)
117 var currentRecord = (results.length < reference + offset ?
118 results.length : reference + offset);
119 docObj.open0;
120 docObj.writeln('<HTML>\n<HEAD>\n<TITLE>Search Results</TITLE>\n
</HEAD>' +
121 '<BODY BGCOLOR=WHITE TEXT=BLACK>' +
122 '<TABLE WIDTH=9O% BORDER=O ALIGN=CENTER CELLPADDING=3><TR><TD>' +
123 '<HR NOSHADE W I D T H = l O O % > < / T D > < / T R > < T R 2 < T D VALIGN=TOP>' +
124 '<FONT FACE=Arial><B>Search Query: <I>' +
125 parent.frames[O].document.forms[O].query.value+ '</I><BR>\n'+
126 'Search Results: <I>' + (reference + 1) + ' - ' +
127 currentRecord + of ' + results.length + '</I><BR><BR></FONT>'+
128 '<FONT FACE=Arial SIZE=-l><B>' +
129 '\n\n<!--Begin result set //-->\n\n\t<DL>');
130 if (searchType == SEARCHURL) {
131 for (var i = reference; i < currentRecord; i++) (
132 var divide = results[il.split("~");
133 docObj.writeln('\t<DT>'+ '<A HREF="' + divideL21 + "'>I +
134 divide[2] + '</A>\t<DD>'+ '<I>' + divide[l] +
'</I><P>\n\n');
135 I
136 }
137 else {
138 for (var i = reference; i < currentRecord; i + + ) {
42 Motor de busqueda para el cliente
Hay mucho codigo. Per0 es muy fhcil comprender quC hace. Empezaremos
desde arriba e iremos bajando poco a poco. Afortunadamente, el codigo se ha
escrito para que ejecute una funcibn detras de otras siguiendo mas o menos el
mismo orden.
Las examinaremos en el siguiente orden:
records.js
El primer elemento que veremos sera el archivo de codigo fuente en JavaScript,
record.js. En la linea 5 tenemos la etiqueta < S C R I P T > .
Contiene un conjunto de elementos denominados perfiles. Vamos a suprimir su
contenido, aunque se ha de ver como una unidad. Asi que, despuks de
descomprimir el contenido del archivo ZIP que se puede bajar de la direccion de
Internet que hemos comentado con anterioridad, abriremos nuestro editor de
texto y cargaremos el archivo recordsjs. Hemos de tener cuidado, porque se
trata de nuestra base de datos. Cada uno de 10s elementos forma parte de una
cadena de tres eslabones. Por ejemplo:
Las distintas partes del registro estan separadas por una barra vertical (I).
Estos caracteres son de gran utilidad cuando imprimimos el contenido del regis-
tro en la pantalla. La segunda parte es el titulo del documento (no tiene nada
que ver con el contenido de las etiquetas TITLE) y la tercera es la descripcion del
documento. La primera, que no hemos comentado, es el URL.
Por cierto, no hay ninguna regla que impida utilizar otro caracter que no sea
" I " para separar las partes del registro. Per0 hemos de asegurarnos de seleccio-
clonsulta (por ejemplo, & " o -[%). No conviene utilizar la barra invertida.
JavaScript la interpreta como el caracter Esc y mostrara unos resultados bas-
tante extrafios.
LPor quk se incluye todo este material dentro del archivo de c6digo fuente?
Por dos razones: modularidad y limpieza. Si el sitio web tiene varios cientos de
paginas Web, es posible que queramos disponer de un programa que genere el
c6digo que contiene todos 10s registros. En cualquier caso, siempre estara mejor
organizado si se encarga de su generation u n archivo codigo fuente en
JavaScript.
Podemos utilizar esta base de datos con otras aplicaciones de bdsqueda. Todo
lo que hemos de hacer es incluir el archivo records.js dentro del codigo. Ademas,
de esta forma evitaremos mostrar el codigo en el archivo HTML.
var SEARCHANY = 1;
var SEARCHALL = 2;
var SEARCHURL = 4;
var searchType = " ;
var showMatches = 10;
var currentMatch = 0;
var copyArray = new Array( ) ;
var docObj = parent.frames [ 1 I .document;
46 M o t o r de busaueda Dara el cliente
currenma tch
Determina quC registro aparecera el primero en la pagina de resultados.
copyArray
Copia el array temporal de registros usados para mostrar 10s siguientes o an-
teriores resultados.
docObj
Variable que se refiere a1 objeto del documento del segundo cuadro. No tiene
demasiada importancia para la aplicacibn, per0 ayuda a controlar el codigo
porque podremos acceder a1 objeto (parent, frames [ 11 . document) varias
veces durante la impresion de resultados. docObj se refiere a este objeto, con lo
que se reduce la cantidad de codigo. Ademas se puede actuar sobre 61 para efec-
tuar modificaciones.
Las funciones
A continuation vamos a ver las funciones mas importantes:
validate()
Cuando el usuario pulsa Intro, la funcion validate ( ) de la linea 18 determi-
na quC quiere encontrar el usuario y procede a buscarlo. N o olvidemos estas
tres opciones:
if (entry.substring(0,4)== "url:") {
entry = entry.substring(5,entry.length);
searchType = SEARCHURL;
I
iY quC pasa con 10s mCtodos substring ( ) que se encuentran entre las lineas
20 y 24? Bien, despuCs de que validate ( ) sepa quk tiene que localizar y como
ha de hacerlo, estos indicadores (+ y url:) dejaran de ser necesarios. Por lo
tanto, validate ( ) elimina el numero de caracteres necesarios del inicio de la
cadena y continua trabajando.
+
Si en el inicio de la cadena no hay ningun ni url:, validate ( ) asignara el
valor SEARCHANY a la variable searchType y procede a limpiar la cadena antes de
llamara a convertstring ( 1 . Las declaraciones while que se encuentran entre
las lineas 28 y 32 eliminan 10s espacios en blanco que se encuentran a1 principio
y a1 final de la cadena.
DespuCs de determinar las preferencias del usuario y eliminar 10s espacios en
blanco sobrantes, validate ( ) se tiene que asegurar que queda algo dentro de
la cadena de busqueda. En la linea 36 se procede a la verificacion. Mira si la
cadena de busqueda contiene, por lo menos, tres caracteres. Si hay menos, no se
generara ningun resultado. De todas formas, siempre podemos modificar esta
configuracion :
if (entry.length < 3 ) {
alert("You cannot search strings that small. Elaborate a little.");
document.forms[0l.query.focus~);
return;
I
rio sirviendose de 10s espacios en blanco y guarda el resultado dentro del array
searchArray. Esto tiene lugar en la linea 45:
function allowAny(t) {
var findings = new A r r a y ( 0 ) ;
for ( i = 0; i < profiles.length; i + + ) {
var compareElement = profiles [ i 1 . touppercase ( ) ;
if(searchType == SEARCHANY) {
var refineElement = compareElement.substring(0,
compareElement.indexOf('IHTTP')) ;
}
else {
var refineElement =
compareElement.substring(compareElement.indexOf('IHTTP'),
compareElement.1ength);
}
for ( j = 0 ; j < t.length; j + + ) {
var comparestring = t[jl.toUpperCaseO;
i f (refineElement.indexOf(compareString) ! = - 1 )
findings[findings.lengthl = profiles[il;
break;
1
Lo que se esconde dentro de las tres funciones de busqueda son una serie de
cadenas de comparacion anidadas por medio de buclesfor. El primero se encarga
Motor de blisqueda para el cliente 49
de repetir cada uno de 10s elementos del array profiles (desde el archivo de codi-
go fuente). Para cada uno de ellos, el segundo bucle hace lo propio con 10s
tkrminos de la peticion que recibe de convertstring( .
Para asegurarse de que el usuario no pierde documentos por haber escrito 10s
tkrminos en mayusculas o minusculas, en las lineas 5 3 y 64 se declaran las
variables,locales compareElernent y cornparestring, respectivamente, y se inicia la
version en mayusculas de cada uno de 10s registros de la cadena. Ahora, no
importara que el usuario escriba “JavaScript”, ’2avascript” o ”jAvasCRIpt”.
alloyArray ( ) aun tiene que determinar si buscar5 el titulo y descripcion del
documento o se basara unicamente en el URL. Asi que la variable local
refineElement, la subcadena que se comparara con 10s terminos de la peticih, se
configurara de acuerdo con el valor de searchvpe (lineas 55 6 5 9 ) . Si searchType
es igual a SEARCHANT, el valor de refineElernent sera el de la subcadena que
contenga el titulo y descripcion del documento. Por el contrario, si searchType es
igual a SEARCHURL, el valor de reJneElernent sera tal que unicamente mostrara
el URL del documento.
LRecuerda 10s simbolos ? Gracias a ellos JavaScript distingue las diferentes
partes del registro. Asi, el mktodo substring( ) devuelve una cadena que em-
pieza en 0 y termina en el caracter que se encuentra antes del primer ‘‘ I HTTP”,
o bien devuelve una cadena que empieza con el primer I HTTP” y termina en el
I‘
ultimo elemento. Ahora comparamos lo que tenemos con 10s valores que ha
introducido el usuario. Miramos la linea 6 5 :
if (refineElement.indexOf(compareString)! = -1) {
findings[findings.lengthl = profiles[il;
break;
}
function requireAll(t) (
var findings = new Array();
for (i = 0 ; i < profiles.length; i++) {
var allconfirmation = true;
var allstring = profiles[il .touppercase();
var refineAllString = allString.substring(0,
allString.indexOf(‘ IHTTP‘)) ;
for (j = 0; j < t.length; j++) (
var allElement = t[jl.toUpperCase();
if (refineA11String.indexOf(allElement) = = -1) {
allconfirmation = false;
continue ;
1
1
if (allconfirmation) (
findings[findings.length] = profiles[i];
}
I
verifyManage(findings);
}
A primera vista, las cosas se parecen mucho a allowAny(). Los buclesfor ani-
dados, la conversion a mayusculas y la variable de confirmation. Todo aparece
aqui otra vez. Per0 las cosas cambian en las lineas 79-80:
i f (refineA11String.indexOf(allElement) == -1) {
allconfirmation = false;
continue ;
I
copyArray = resultSet.sort0;
formatResults(copyArray, currentMatch, showMatches);
1
function noMatch ( ) {
docObj . open ( ) ;
docObj.writeln('<HTML><HEAD><TITLE>SearchResults</TITLE></HEAD>'t
'<BODY BGCOLOR=WHITE TEXT=BLACK>' +
Motor de bljsqueda para el cliente 55
formatResults()
El trabajo de esta funci6n es mostrar 10s resultados a1 usuario con un formato
agradable. No es nada complicado, per0 se encarga de hacer bastantes cosas.
Estos son 10s ingredientes con 10s que trabaja para escribir 10s resultados en la
pantalla:
Una cabecera HTML, un titulo y un cuerpo de texto.
El titulo, descripcih y URL de cada uno de 10s registros, ademas de un
enlace a1 URL de cada registro.
Botones para avanzar y retroceder a 10s registros posteriores y anteriores
(respectivamente), siempre que Sean necesarios, claro.
Per0 las cosas empiezan a complicarse algo mas en la linea 126. Aqui se inicia
el conjunto de resultados. L a linea del texto impreso que aparece en la pagina
mostrara una parte de 10s registros y el numero total de documentos localiza-
dos. Por ejemplo:
Search Results: 1 - 10 of 3 8
formatResult(copyArray,currentMatch, showMatches);
Search Results: 20 - 30 of 38
Search Results: 20 - 3 8 of 38
Search Results: 30 - 40 of 38
if (searchType == SEARCHURL) {
for (var i = reference; i < currentRecord; i++) {
var divide = r e s u l t s [ i ] . s p l i t ( ’ ~ ’ ) ;
docObj.writeln(’\t<DT>’ + ‘ < A HREF=”’ + divider21 + ’ “ > ’ +
divide[2] + ’ < / A > ‘ + ’\t<DD>‘ + ’ < I > ‘ + divide[l] + ’ < /
I><P>\n\n‘);
I
1
58 Motor de blisqueda para el cliente
else {
for (var i = reference; i < currentRecord; i++) {
var divide = results[i].split(’I ‘ ) ;
docObj.writeln( ‘\n\n\t<DT>’+ ’ < A HREF=”’ + divide[2] + ’ ” > ’ +
divide[O] + ‘ < / A > ‘ + ‘\t<DD>’+ ’<I>’+ divide[l] + ’ < / I > < P > ’ ) ;
}
1
Las lineas 131 y 138 muestran 10s dos bucles que desarrollan la misma opera-
cion que currentRecord, con una salvedad, el orden de 10s elementos impreso es
distinto. Nos volvemos a encontrar con la variable searchType. Si es igual a
SEARCHURL, la aplicacion mostrara el URL como un hipervinculo. Si equivale a
SEARCHANY o SEARCHALL se mostrarh el titulo del documento dentro del
hipervinculo.
Ya hemos determinado el tip0 de busqueda, per0 icomo mostramos 10s resul-
tados? Unicamente necesitaremos un subconjunto de registros, separarlos por
titulo, descripcion y URL y colocarlos en la pantalla como queramos. Este es el
buclefor que utilizaremos en ambos casos (es decir, tanto si se utiliza la busque-
da URL como si no):
Esta explicacion puede parecer demasiado basica, pero por lo menos ya sabe-
mos cuando tenemos que incluir 10s botones. Las declaraciones que se encargan
de ello son las que se encuentran en las lineas 154 y 160. Incluyen uno o dos
botones, dependiendo del subconjunto de registros que aparezcan en pantalla y
de 10s que queden fuera.
Motor de blisqueda para el cliente 61
‘onClick=”’+parent.frames[0].formatResults(parent.frames[0].copyArray,
+ (reference - offset) + ’ , ’ + offset + I ) ” > ’ ) ;
Al principio nos puede parecer algo extrafio. Per0 no olvidemos que la llamada
a f o r m a t R e s u l t s ( ) no se inicia en nav.htrnl ( p a r e n t . f r a m e s [ 0 ] ) , sin0 en el
marco del resultado p a r e n t . f r a m e s [ 1] que no tiene ninguna funcion que se
llame f o r m a t R e s u l t s ( ) ni ninguna variable llamada copyArray. Por lo tanto,
las funciones y variables necesitan estas referencias.
El b o t h ”Next” obtiene una llamada similar del controlador del evento onCZick.
Pero, u n momento. iNo deberiamos tener en cuenta la posibilidad de que offset
tenga menos resultados que copyArray como hicimos con f o r m a t R e s u l t s ( )
cuando tratabamos de determinar el plural/singular de la palabra ”Results” No.
La funcion f o r m a t R e s u l t s ( ) ya tiene en cuenta esa decision. Todo lo que
tenemos que hacer es sumar reference a offset y pasarlo. Vamos a ver el conteni-
do de las lineas 166-167, de nuevo la segunda parte de metodo de llamada
document .writeln():
’
’onClick=”parent.frames[0].formatResults(parent.frames[0l.copyArray,
+ (reference + offset) + ‘ , ’ + offset + ‘)”>‘);
64 Motor de busaueda Dara el cliente
El codigo HTML
El archivo navhtml apenas contiene codigo HTML. Este es su contenido (em-
pezando en la linea 174):
</HEAD>
<BODY BGCOLOR="WHITE" >
<TABLE WIDTH="95%" BORDER="0 " ALIGN="CENTER">
<TR>
<TD VALIGN=MIDDLE>
<FONT FACE= "ATial " >
<B>Client-Side Search Engine</B>
< / TD>
<TD VALIGN=ABSMIDDLE>
<FORM NAME = " search"
onsubmit="validate(document.forms[0l.query.value); return false;">
<INPUT TYPE=TEXT NAME= "query" SIZE="33 " >
<INPUT TYPE=HIDDEN NAME="standin" VALUE="">
< /FORM>
</TD>
< T D VALIGN=ABSMIDDLE>
<FONT FACE= "Aria1 " >
< B x A HREF="main.html" TARGET="main">Help</A></B>
</TD>
</TR>
< /TABLE>
</BODY>
</HTML>
“Your_Page_TitlelYour_Page_Descriptionlhttp://your-page-url/
file-name.html”,
Entre 10s parCntesis podremos incluir tantos elementos como queramos. Per0
hemos de asegurarnos de incluir la coma despuks de cada registro (menos en el
ultimo). ObsCrvese que tambien ahora el titulo, descripcion y URL del documento
estan separados por el caracter I. No debemos utilizarlo dentro de 10s titulos,
descripciones o URL, ya que nos encontrariamos con problemas. Ademas, si in-
cluimos comillas dobles (”), aparte de las que aparecen en 10s extremos, hemos de
asegurarnos de inchir la barra invertida delante de ellas (es decir, \“ en vez de ”).
Posibles aplicaciones
El motor de busqueda es muy util. Per0 seguro que se puede mejorar con unos
cuantos cambios, como por ejemplo:
aun me sorprendo con el numero de visitantes que navegan por mis paginas
Web con navegadores anteriores a estos dos.
Como un motor de busqueda es una de las aplicaciones mas importantes del
sitio Web conviene que consideremos la posibilidad de hacerlo compatible con
JavaScript 1 .O. Todo lo que tenemos que hacer es recorrer el codigo que hemos
visto a1 principio del capitulo, linea a linea, ver quk propiedades no acepta la
version 1.O de JavaScript y cambiarlas todas.
Bien. Yo ya lo he hecho. Ahora le toca a usted. En esta seccion veremos aque-
110s aspectos que permiten que la aplicacion funcione con 10s exploradores
JavaScript 1.O. Hay tres cambios:
N N 2.x y MSIE 3.x no pueden trabajar con 10s archivos de codigo fuente .js
(aunque hay algunas excepciones). La solucion es incluir el array de perfiles
dentro del archivo nav.html. Con el segundo cambio eliminaremos la llamada a
result.sort ( ) de la linea 90. Es decir, que 10s resultados no se ordenaran
alfabkticamente, sino en el mismo orden cronologico con que aparecen dentro
de profiles. El ultimo cambio sera eliminar el mktodo split ( ) . JavaScript 1.0
tampoco lo admite. La solucion alternativa lo solucionara, per0 se pierde en
r endimiento.
Dificultar su ruptura
Podemos pasar el conjunto de caracteres como parte de la cadena de busqueda.
iPor q u i no agregar una funcion que elimine 10s caracteres de la cadena que se
utilice como separadores? De esta forma, sera mas complicado que la aplicacion
se llegue a romper.
podemos incluir otros como NOT, ONLY o EVEN. En lineas generales, estos son
sus significados:
AND
El registro ha de contener 10s dos terminos que se encuentren a derecha y a
izquierda de AND.
OR
El registro ha de contener cualquiera de 10s dos ttrminos que se encuentren a
derecha y a izquierda de OR.
NOT
El registro no puede contener el termino que se encuentre a la derecha de NOT.
ONLY
El registro unicamente podra contener este termino.
LIKE
El registro contendra cualquier termino que se parezca a1 deseado.
Conjunto de agrupaciones
Otra tkcnica que se usa mucho es establecer conjuntos de agrupaciones. Se
trata de grupos predeterminados de palabras que devuelven automaticamente
una serie de resultados predeterminados. Por ejemplo, si un usuario incluye el
termino "fondos de mutualidad" en la cadena de peticion, automaticamente se
puede generar una lista de resultados que contengan registros de 10s productos
que ofrezca nuestra compaiiia de seguros. Esta tecnica necesita mas prepara-
cion, per0 es ideal para las aplicaciones de busqueda.
Capitulo 2
Examen online
Question 1 of 50
You unsuccessfullyuse nwigrtor.prefennces0 to alter browser preferences. How come?
Quesbon 2
5. Segun se revisen 10s resultados, el usuario podra colocar el raton sobre una
de las respuestas fallidas (texto en rojo) para que la aplicacion muestre mas
informacion.
Question 4
Select the method added in JmaScnpt 1 2
a concat0
b link0
c spittg)
d pno
’* i
Question 6
What is one disadvantage of using the Function constructor7
Requisitos de la ejecucion
Todo el codigo ha sido escrito en JavaScript 1 . 1 , motivo por el que unicamente
se podra trabajar con exploradores que Sean del tip0 Navigator 3.x (0superior)
y MSIE 4.x (0 superior). El examen incluye t a m b i h un total de 400 preguntas.
La verdad es que no creo que nadie lo vaya a utilizar para proporcionar un cer-
tificado a sus alumnos, por lo que consider0 que 400 preguntas son mas que
suficientes.
Analisis de la sintaxis
En la figura 2.5 podemos comprobar el esquema que muestra 10s pasos que rea-
lizara el usuario desde el momento en que inicia el examen hasta que lo termi-
na. Si queremos comprender lo que ocurre en realidad deberiamos trabajar con
otro esquema que resulte mas completo y analizar el codigo fuente correspon-
diente a 10s archivos.
Examen online 73
En la figura 2.6 tenemos ese esquema. Los cuadros discontinuos indican que el
proceso se hara antes o despues de la prueba (por ejemplo, durante la carga de las
paginas Web). Las flechas discontinuas indican que se esta esperando que el usua-
rio haga algo. La funcion asociada con cada proceso aparecera en cursiva.
Compare el grafico de la figura 2.5 con el de la figura 2.6. Es la mejor forma de
detectar las diferencias. El esquema es el mismo, solo que ahora podemos ver
que ocurre antes y despues de que el usuario seleccione una opcion del test.
index.html
La aplicacion tiene tres archivos: index.htm1, administer.htmZ y questions.js.
Como index.htm1 es el archivo desde el que se iniciara el proceso, empezaremos
con 61. En el ejemplo 2.1 podemos ver su contenido.
74 Examen online
El usuario
selecciona BEGlN
(iternReset())
I
El usuario ve
I
I
a inforrnacion
sobre la respuesta
1 <HTML>
2 <HEAD>
Examen online 75
administerhtml se vale del atributo SRC para crear la etiqueta FRAME pero, ique
hay de las otras dos? Las dos variables dummy definen las piiginas HTML. Es
decir, que dummy1 y dummy2 representan paginas HTML sin ningun nombre.
Unicamente existen dentro de la aplicacion. Estas variables se definen en las li-
neas 7 y 8. Cada una de ellas contiene una pequeiia parte de HTML. No mucho,
lo suficiente para que funcionen. index.htm1 utiliza el protocolo j avascript :
76 Examen online
14 "Password", "Area") ,
15 / / etc . . .
16
Se parece a cualquier funcion que pudiksemos crear, solo que aqui se utiliza la
clave t h i s para referirse a si misma. Los argumentos que pasemos se podran
asignar a propiedades o manipular de distintas maneras. Una vez que tenga-
mos el constructor, tendremos que iniciar las variables con el nuevo operador:
this.answer = answer;
this.support = support;
this.question = question;
this.a = a;
this.b = b;
this.c = c;
this.d = d;
return this;
>
Las propiedades y mktodos se asignan generalmente a objetos. Para ello se uti-
liza la notacion this.De esta manera, cada uno de 10s elementos pertenecientes
a units utiliza el operador new con objeto de crear un nuevo caso de ques tion ( ) ,
a1 que se le entregan 10s siete parametros. En la linea 9 , encontramos la siguien-
te sintaxis:
return this;
Esta linea devuelve una referencia a la variable iniciada (en nuestro caso, cada
uno de 10s elementos units).Ahora cada elemento de units es question. Es el
sistema que se ha de utilizar para crear, eliminar y manipular las preguntas de
nuestro examen. Podemos agregar mas preguntas utilizando la misma sintaxis
con otros elementos units:
administer. ht mI
A continuacion colocamos cada objeto en su sitio. Vamos a hacer que trabajen
para nosotros. Se trata de otra de las aplicaciones donde el cerebro de la aplica-
cion en JavaScript se encuentra en el cuadro superior de la pantalla, mientras se
deja el cuadro inferior para que interactue con el usuario. Podemos separar la
aplicacion en una serie de procesos. En la tabla 2.1 tenemos la descripcion de
dichos procesos y las variables y funciones de JavaScript asociados con ellos.
Tabla 2.1. Procesos del examen y las funciones JavaScript asociadas
11 =
58 this.value; parent.frames[Ol.buildQuestion()">'+ optAnswer +
' <BR> ;
59 I
60 function chickenout0 {
61 if(stop0K & & confirm('Stopping early? Are you really a ' +
62 'JavaScript Chicken?')) {
63 gradeTest ( ) ;
64 )
65 1
66 function gradeTest0 {
67 for (var i = 0; i < qIdx; i++) {
68 if (keeper[il = = units[il .answer) {
69 correct++;
70 I
71 }
72 var idx = Math.ceil((correct/howMany) * rank.length - 1) < 0 ?
0 :
73 Math.ceil((correct/howMany) * rank.length - 1);
14 printResults(rank[idxl);
75 itemReset ( ) ;
76 I
77 function printResults(rankin9) {
78 results = '<HTML><BODY BGCOLOR=WHITE LINK=RED VLINK=RED
ALINK=RED> ' +
79 '<FONT FACE=Arial>' +
80 '<H2>Youscored ' + correct + ' / ' + howMany + ' correctly.<
H2>' +
81 '<B>Ranking: <I>' + ranking +
82 '</I><BR>Passthe mouse over the red text for an explanation
of ' +
83 'those you misssed.</B>' +
84 '<BR><BR><FONT SIZE=4>Here is how you scored: </FONT><BR><BR>';
85 for (var i = 0; i < howMany; i++) {
86 results += '\n\r\n\r\n\r<B>Question' + (i + 1) + '</B><BR>'
87 + units[i].question + '<BR><BR>\n\r<FONTSIZE=-l>' +
88 'a. ' + units1il.a + '<BR>'+
89 'b. ' + units[i].b + '<BR>' +
90 'c. ' + unitsLi1.c + '<BR>'+
82 Examen online
Este archivo tan grande se puede separar en cuatro secciones. En primer lugar
tenemos la llamada a1 fichero questions.js.A continuacion la definicion de algu-
nas variables globales. DespuCs aparecen las funciones y por ultimo, tenemos
Examen online 83
unas cuantas lineas de HTML. Vamos a empezar por aqui, mas que nada porque
es la parte mas sencilla.
El cuerpo HTML
Cuando se completa la carga de adrninister.htrnl, entonces se llama a la funcion
cleanslate ( 1 en la linea 125:
function cleanslate0 {
aFrame.location.replace('javascript: parent.dummy1');
qFrame.location.replace('javascript: parent.dummy2');
}
Ya lo hicimos en index.htrnZ, iverdad? Si. Ya lo hemos hecho. Per0 esta vez, nos
aseguramos de que si el usuario vuelve a cargar administer.htm1 por la razon
que sea, el cuadro que se encuentra en la parte superior de la pagina, siempre se
abrira como una pagina en blanco, y que el cuadro inferior se abrira con el men-
saje "bucko". Ademas, el usuario no podra acceder a1 contenido anterior de la
pagina, motivo por el cual si este consistiese en una pregunta, no podra corregir
su respuesta.
El resto del HTML no es otra cosa que un formulario con dos botones. No nos
vamos a extender en esta parte. El archivo administer.htm1 tiene un formulario
con dos botones. Cada uno de ellos llama a funciones diferentes cuando se hace
clic sobre ellos. Este es el c6digo que se encuentra en las lineas 127-132:
<FORM>
<INPUT TYPE=BUTTON VALUE="Begin"
onclick="itemReset ( ) ; buildQuestion(): " >
 :
<INPUT TYPE=BUTTON VALUE="Quit Now" onclick="chickenOut ( ) ; " >
< /FORM>
Variables globales
Justo despuks del codigo que llama a1 archivo questionsjs de la linea4, tenemos
las variables globales que se utilizaran en la aplicacion. Se encuentran en las
lineas 5-22:
var qIdx = 0;
var correct = 0;
var howMany = 50;
var keeper = new Array( ) ;
var rank = new Array('No offense, hut you need help.'
' Ummm... Well . . . Few have done worse.',
'Ehhh. . . You know some. Keep at it.',
'You seem to have a working knowledge.',
'Better than the average hear.',
'You are an adequate JavaScripter.',
'You are a formidable JavaScripter.',
'You are an excellent JavaScripter.',
'You are an exhalted JavaScript guru.'
);
var stopOK = false;
var nextQ = ";
var results = ";
var aFrame = parent.frames[l];
var qFrame = parent.frames [2];
qldx. Una variable que se utiliza para visualizar la pregunta que figura en
la pantalla.
carrect. Variable que se utiliza para registrar el numero de respuestas
correctas.
howMany. Numero fijo que determina el numero de preguntas que quiere
responder el usuario (independiente del nombre que se encuentra en el
array units)
keeper. Array que inicialmente esta vacio donde se guardan las respuestas
del usuario.
rank. Array de cadenas que indican 10s distintos niveles e eficacia.
stopOK. Variable que contiene un valor booleano que indica cuando se
puede detener el examen antes de que Cste llegue a su fin.
nextQ. Cadena vacia a la que se le asigna repetidamente el valor de HTML
que representa cada una de las preguntas del examen.
results. Cadena vacia a la que se le asigna el valor de HTML que representa
10s resultados del examen.
Examen online 85
Funciones
Ahora vamos a ver las funciones. Empezamos con itemReset().
itemReset()
L a primera funcion a la que se llama en esta aplicacion es itemReset ( 1 . Tiene
lugar cuando el usuario selecciona el boton "Begin" (lineas 128-129):
itemReset ( ) asigna a las variables globales su valor original y mezcla las pre-
guntas en un array de elementos. Su codigo se encuentra en las lineas 31-37:
function itemReset0 {
qIdx = 0;
correct = 0;
stopOK = false;
keeper = new Array( ) ;
shuffle();
1
shuffle()
Esta pequeiia funcion permite que el administrador de la aplicacion trabaje
con cierta flexibilidad. Se encarga de desordenar las preguntas, con lo que casi se
garantizara que cada usuario accedera a una version unica del examen. Para
hacernos una idea de las posibilidades, consideremos por u n momento que el
86 Exarnen online
function s h u f f l e 0 {
for (var i = 0; i < units.length; i++) I
var j = Math.floor(Math.random() units.length);
var tempunit = units[il;
units[i] = units[jl;
units[j] = tempunit;
1
I
I
Examen online 87
function buildQuestion0 {
if (qIdx == howMany) {
gradeTest ( ) ;
return;
)
nextQ = '<HTML><BODYBGCOLOR=WHITE><FONTFACE=Arial>' +
'<H2>Question ' + (qIdx + 1) + ' of ' + howMany + '</H2>'+
' < F O R M > ' + '<B>'+ units[qIdx].question + '</B><BR><BR>'
+
makeButton("a", unitsrqIdx1 .a) +
makeButton ( "b", units [qIdxl .b) +
makeButton("c",units[qIdxl .c) +
makeButton("d", units[qIdxl .d) +
'</FORM></BODY></HTML>';
qFrame.location.replace("javascript:parent.frames Lo1 .nextQ");
qIdx++;
if(q1dx >= 2 & & !stopOK) { stopOK = true; )
1
A continuation, veremos que se abre una etiqueta FORM a la que sigue el texto
de la pregunta. Si hacemos un poco de memoria, recordaremos que el texto de la
pregunta se encuentra dentro de la propiedad question de cada elemento units.
Luego no ha de sorprendernos encontrarnos este codigo en la linea 45:
Y donde encontremos una etiqueta FORM, cerca tendremos 10s elementos del
formulario. En realidad, esto es todo lo que se necesita para construir una pagi-
na HTML. Este formulario unicamente tiene cuatro elementos (cuatro botones
de opcion). En vez de escribir el codigo HTML encargado de la creacion de 10s
cuatro botones de opcion dentro de la funcion (casi seria repetir cuatro veces lo
mismo), tenemos la funcionmakeButton ( ) que se encargara de generarla. Uni-
camente tendremos que pasarle la letra y el texto de cada una de las opciones
(lineas 46-49). Este es el contenido de la funcion makeButton ( ) que se encuen-
tra en las lineas 55-59.
Esta funcion se limita a devolver una cadena que representa un boton de opcion
con una serie de atributos personalizados (VALUE) que equivalen a a, b, c o d,
Examen online 89
seguido del texto que aparecera a su derecha. Los atributos VALUE proceden de
optLtr y el texto de optAnswer.
N o olvidemos que quien lleva las riendas del examen es el mismo usuario, por
eso sera 61 quien determinara el momento en que se pasara a la siguiente pregun-
ta. En JavaScript esto quiere decir que, a1 asociar las expresiones de cada opci6n
con el controlador de eventos onclick, ocurriran un par de cosas.
En primer lugar, el array keeper guardara la letra asociada a la respuesta selec-
cionada por el usuario. Para determinar a quC elemento se le asignar6 la respues-
ta del usuario, utilizamos el siguiente codigo:
La variable qldx guardara un registro con la cuenta de las preguntas que ayu-
dara a la hora de asignar el siguiente elemento que seleccione el usuario.
La segunda "cosal' que ocurre es que JavaScript llama a buidQuestion ( 1 para
que imprima la siguiente pregunta en la pantalla o para que proceda con la va-
loracion del examen, si la respuesta contestada era la ultima. Tanto keeper como
buidQuestion ( ) empiezan en parent. frames [ 01. Puesto que la informacion
se guardara aqui, tendremos que acceder a ellos desde el cuadro superior de la
pagina.
Cuando completemos la construccion del formulario, lo unico que nos queda-
ra por hacer (por lo menos, en lo que se refiere a1 codigo HTML) es cerrar las
etiquetas y cargar el contenido en las ventanas. VCanse las lineas 50-5 1 :
'</FoRM></BoDY>I/nTML>';
qFrame.location.replace("javascript: parent.framesI0l.nextQ");
qIdx++;
if(q1dx >= 2 && !stopOK) { stopOK = t r u e ; 1
90 Examen online
gradeTest()
La funcion gradeTest ( ) tiene dos fines. El primer0 es comparar las respues-
tas de 10s usuarios con las respuestas correctas, llevando la cuenta de 10s aciertos.
La segunda, es calcular el indice de acierto y responder basandose en el numero
de respuestas acertadas. Se define en las lineas 66-76 del codigo:
El array keeper contiene cada una de las letras (a,b, c o d) asociadas con las res-
puestas que podra escoger el usuario en cada una de las preguntas. Cada ele-
mento del array units es un objeto de una pregunta que contiene una propiedad
answer (a,b, c o d).gradeText ( ) actua sobre cada uno de 10s elementos keeper
y compara su valor con el de la propiedad answer del elemento units correspon-
diente. Si hay un acierto, entonces el valor de la variable correct se aumentara
una unidad.
Obskrvese que esta funcion no guarda un registro con las respuestas correctas.
De hecho, esto nunca ocurrira en esta aplicacion. La funcion se limita a deter-
minar el numero de respuestas correctas y a calificar el examen basandose en
dicho numero. Cuando revisemos la funcion printResults ( volveremos a
revisar el array keeper. TambiCn conviene destacar que gradeTest ( ) no actua
sobre todas y cada una de las preguntas howMany. No importa la cantidad de
preguntas que tenga el examen. El usuario solo las podra contestar una vez.
Una vez que se obtienen 10s resultados, la variable correct contendra el numero
de respuestas correctas. gradeTest ( ) solo tiene que determinar la calificacion
del usuario. Las lineas 72-73 se encargan de ello.
El resultado del proceso se guarda en la variable local idx, que es un entero pro-
porcional a la efectividad del usuario, cuyo valor estara comprendido entre 0 y
rank. length.En otras palabras, no importa la cantidad de preguntas que haya.
El usuario siempre recibira una calificacion que se basara en el numero de res-
puestas acertadas. El siguiente ejemplo nos ayudara a comprenderlo mejor. Su-
pongamos que la configuracion del array rank es la siguiente:
var rank = new Array( "Los he visto mejores", " N o esta mal", "Bien",
"Muy bien" , "Excelente")
printResults0
L a aplicacion ya conoce la calificacion del usuario. Ahora se la tiene que mos-
trar. La f u n c i 6 n p r i n t R e s u l t s ( ) se encarga de mostrar en pantalla 10s siguien-
tes elementos:
function printResults(ranking) {
results = '<HTML></HEAD><BODYBGCOLOR=WHITE LINK=RED VLINK=RED
ALINK=RED>'+
'<FONT FACE=Arial>' +
'<H2>You scored ' + correct + ' / ' + howMany + correctly.</H2>' +
'<B>Ranking: <I>' + ranking +
'</I><BR>Passthe mouse over the red text for an explanation of ' +
'those you misssed.</B>' +
'<BR><BR><FONTSIZE=Q>Here is how you scored: </FONT><BR><BR>';
if (keeper[il == units[il.answer) {
results += '<B><I><FONTCOLOR=GREEN>' +
'You answered this correctly ( ' + keeper[il + ' ) . ' +
'</FONT></I></B>\n\r<BR><BR><BR>';
I
else {
results += '<FONT FACE=Arial><B><I>'+ '
' < A HREF=" " onMouseOver="parent.frames[Ol .show(); ' +
parent.frames[Ol.explain(\" + units[i].support + ' \ ' ) ; ' +
' return true" onMouseOut="parent . frames 101 .explain ( \ ' \ * ) ;" ' +
'onClick="return false; " > ' +
'The correct answer is: ' + units[i].answer +
'</A></FONT></I></B>\n\r<BR><BR>';
I
I
Para cada pregunta, el usuario seleccionara una respuesta, que puede ser correc-
ta o incorrecta. Para determinarlo se utiliza una declaracion if-else. Si keeper [ i 3
es igual a units [ i ] .answer, la respuesta del usuario habra sido la correcta.
Por lo tanto, un texto en verde mostrara el contenido de la respuesta (keeper[ i 3 ).
Si no coinciden, aparecera un texto en rojo que permitira acceder a una infor-
maci6n adicional en la cual se mostrara informacion acerca de la respuesta en
parent. frames [ 1] . Este cuadro se utilizara para mostrar este tip0 de infor-
macion a1 usuario.
Las respuestas que se hayan contestado correctamente se mostraran como
texto simple. Per0 las incorrectas apareceran en rojo en un texto que tiene u n
hipervinculo. El evento onMouseOver de cada uno de estos vinculos se encargara
de llamar a las dos funciones antes de devolver el valor true. Se trata de show ( )
y explain ( ) . La primera es muy sencilla. Imprime una cadena vacia en la barra
de estado para evitar cualquier distraccion generada a partir de onMouseOver.
Su codigo se encuentra en la linea 10.
function explain(str) {
with (aFrame.document) {
open();
Examen online 95
Aunque ya nos hemos tenido que hacer cargo del evento onMuoseOver, la fun-
cion explain ( ) aun necesitara mas atenciones. Observese que se vuelve a lla-
mar a esta funcion en la linea 101, en el controlador del evento onMouseOut.
Pero esta vez, se le entrega una cadena vacia, de tal forma que parecera que se
limpia el contenido de aFrame despuks de cada evento onMouseOver.
Ahora, solo nos queda evitar que se desencadene alguna accion cuando el usuario
haga clic sobre el hipervinculo de texto que se activa cuando se coloca el punte-
ro sobre d . En la linea 102 encontramos onClick="returnfalse;". Con esta
declaracion cancelamos la carga de cualquier documento que aparezca en el URL
del atributo HREF.
N o olvidemos que aun nos encontramos dentro del buclefor. El proceso ante-
rior se repetira con las respuestas comprendidas entre 0 y howMany - 1. Obvia-
mente, despuks de la ejecucion del bucle, el valor de la variable results sera una
gran cadena que contenga el numero de la respuesta correcta, el numero total de
preguntas del examen, el texto de todas ellas y de sus posibles respuestas, y la
seleccionada por el usuario o la respuesta correcta. En las lineas 107-109 se afia-
de algo de codigo para finalizar el HTML, cargar la cadena dentro del cuadro
inferior de la pantalla y cerrar la funcion.
results += '\n\r</BODY></HTML>';
qFrame.location.replace("javascript: parent.frames[Ol.results");
}
chickenOut()
Permitir que el usuario abandone el examen antes de completarlo representa
un pequeiio problema. La verdad es que no nos hace falta esta opcion para nada
y podemos eliminarla de nuestras implementaciones. La he aiiadido para que el
usuario tenga algo mas de libertad. Su codigo esta entre las lineas 60-65:
function chickenout0 {
if(stop0K & & confirm('Stopping early? Are you really a ' +
'JavaScript Chicken?') I
gradeTest ( ) ;
1
1
Si el usuario puede elegir y confirma que desea salir antes de completar el exa-
men, se llamara a la funcion gradeTest ( ) . Recordemos que u n usuario puede
96 Examen online
Posibles ampliaciones
Esta aplicacion se puede modificar de muchas formas. Per0 las dos mas obvias
(a mi parecer) es mejorar el sistema para que no se pueda hacer trampas a1 ser-
vidor y hacer que la aplicacion tambikn se pueda hacer cargo de encuestas en
vez de limitarse a examenes.
A prueba de trampas
Una de las primeras cosas que tenemos que plantearnos a la hora de desarro-
llar la aplicacion es que 10s usuarios podran revisar las preguntas bajandose el
archivo donde se encuentra en c6digo fuente en JavaScript. Puede llevar algo de
trabajo revisar el codigo para localizar la respuesta correcta a cada pregunta,
per0 se puede hacer.
Podemos eliminar este riesgo no enviando las respuestas con la aplicacion y
solicitando a 10s usuarios que envien sus respuestas a1 servidor para que este se
encargue de su evaluacion. N o haremos la evaluaci6n del examen en el servidor,
per0 tampoco trabajaremos con gradeTest ( ) . Puede ser un poco mas laborio-
so, per0 10s principios a seguir son 10s mismos.
Para eliminar la propiedad de evaluacion y permitir que se pueda enviar el exa-
men a1 servidor, tendremos que hacer lo siguiente:
Eliminar cualquier representacion de las respuestas del objeto y el array del
archivo questions.js.
Eliminar gradeText ( ) y a continuacion sustituir la llamada que se efec-
tua desde b u i l d Q u e s t i o n ( ) con p r i n t R e s u l t s ( ) .
ModificarprintResul t s ( ) de tal forma que el usuario pueda ver sus res-
puestas e incluir estos datos dentro de un formulario HTML para enviar-
selas a1 servidor.
function question(question, a, b, c, d) {
this.question = question;
this.a = a;
this.b = b;
this.c = c;
this.d = d;
return this;
}
ObsCrvese que las variables answer y support tambiCn se han eliminado. Ahora
que no las tenemos en el constructor, las eliminaremos de todas las llamadas que
se efectuen desde el operador new que hay en cada elemento de units. En otras I
if (qIdx == howMany) {
gradeTest ( ) ;
return;
}
se cambiaran por:
i f (qIdx == howMany) I
printResults ( ) ;
98 Examen online
return;
1
Modificar printResults0
En la funcion PrintResults ( ) sera donde tenga lugar la mayor parte del tra-
bajo. La linea 84 de administer.htm1 contiene el siguiente codigo:
La cambiamos por:
results += '\n\r</BODY></HTML>';
Y la cambiamos por:
Automaw
Animal Kingdom Slideshow
Common Name:
Bird
S d a d k kNmc:
Bomb-& Cu-us
Absrract
l h s q c d cicahyc has
brcn known to reek out and
sod bcshly-washed veluclcr
G&O*
Absrrrrt
l h r m s l IS conridcrcd a
moover and shaker. and
tcndr to nvlk thmgr for dl
Analisis de la sintesis
I
El scipt se encuentra dentro del archivo index.html. El ejemplo 3.1 nos muestra
su contenido.
1 <HTML>
2 <HEAD>
3 <TITLE>The Slideshow</TITLE>
45 copy + '</DIV>');
46 I
47 }
48
49 f function slide(imgStr, scientific, copy) {
50 this.name = imgStr;
51 imagePreLoad(imgStr);
52 this.copy = copy;
53 this.structure =
54 '<TABLE WIDTH=500 CELLPADDING=lO><TR><TD WIDTH=60%
VALIGN=TOP>' +
55 '<IMG SRC=' + imgPath + imgStr + '.gif></TD>'+
56 '<TD WIDTH=40% VALIGN=TOP><H2>Common Name:</H2><H2><1>' +
57 camelCap(imgStr) + '</I></H2><H3>ScientificName:
</H3><H3><1>'+
58 scientific + '</I></H3>'+ '<B>Abstract:</B><BR>'+ copy 4
59 '</TD>~/TR></TABLE>';
60
61 return this;
62 1
64 function imagePreLoad(imgStr) {
65 img [img.length] = new Image ( ) ;
66 img[img.length - 11.src = imgPath + imgStr + '.gif';
67
68 imgOut [imgOut.length] = new Image ( ;
69 imgOut[imgOut.length - 11.src = imgPath + imgStr + 'out.gif';
70
71 imgOver[imgOver.lengthl = new Image();
72 imgOver[imgOver.length - 11.src = imgPath + imgStr +
'over.gif';
73 I
74
DiaDositivas interactivas 105
Variables de la aplicacion
Vamos a empezar fijandonos en las variables y en otros detalles. Luego pasare-
mos a las funciones. Este es el contenido de las lineas 5-7:
<STYLE TYPE="text/css">
#menuconstraint { height: 800; )
</STYLE>
Define una hoja de estilos donde 10s elementos se superponen unos a otros, lla-
mada rnenuCunstraint y una unica propiedad: un alto de 800 pixeles. Se aplicara
a todas las diapositivas para asegurarse de que el usuario las puede ver. En otras
palabras, si la resolucion del monitor del usuario tiene una altura inferior a 800
pixeles, la aplicacion mostrara barras de desplazamiento. Este hecho es muy
util cuando nuestras imagenes Sean muy grandes o tengamos que trabajar con
muchas copias. Por lo menos, 10s usuarios que no dispongan de dicha resolu-
cion podran desplazarse por el contenido de la pantalla para ver el resto de la
diapositiva. En las lineas 11-31 tenemos las variables:
En cualquier otro caso, el scipt asumira que se trabaja con MSIE 4.x y asignara
a NN el valor false. El modelo de ohjrtos de Microsoft hace referencia a las capas
layers del objeto styles de docurnentall. Las variables sWidPos y sHgPos contie-
nen 10s valores de las coordenadas x e y de la esquina superior izquierda, donde
se colocara la capa, de tal forma que Cste sera el centro de la ventana del explo-
rador (no de la pantalla). Esto se determina a partir del valor de NN y de las
variables sWidPos y sHgPos. Este es el contenido de las lineas 18-21.
Es muy sencillo. Las imagenes que se guardan en el array img representan las
imagenes de las diapositivas. Las que se encuentran en el array imgOut se utili-
zan para el menu. Las que se encuentran dentro de imgOver se utilizan para el
menu de ejecucion automatica. Volveremos a ver las imagenes relacionadas con
la reproduccion automatica cuando estudiemos la funcion swapImage ( ) .
La ultima variable, imgPath contiene el valor de la ruta del servidor donde se
encuentran las imagenes. Podemos hacer que esta ruta sea absoluta o relativa.
Diarsositivas interactivas 111
Para generar una barra invertida como las utilizadas en el sistema operativo
de Windows tendremos que utilizar dos (\\). Si no lo hacemos, JavaScript pen-
sara que queremos escribir:
C:WinntProfilesAdministratorDesktop;
No se trata de algo que sea incorrecto. Lo unico que provocara sera un error de
sintaxis.
Funciones de la aplicacion
Las funciones de la aplicacion se agrupan en tres categorias diferentes: crea-
cion de la capa, control de la imagen y navegacion/pantalla. En la tabla 3 . 1 po-
demos ver la descripcion de cada una de ellas y t a m b i h se especifica la clase a la
que pertenece.
112 DiaDositivas interactivas
genlayero
Esta funcion DHTML vale para todos 10s exploradores. Cualquier cosa que se
quiera mostrar en la pantalla, independientemente de su tamaiio, cantidad de co-
lores, etc, debe pasar por esta funcion. Su c6digo esta en las lineas 33-47:
return this;
}
DiaDositivas interactivas 115
else ( / / Ea %a
/ / Trabeja can JavaScr€pt
/ / ep. e j . documeint:.layerr, atc.
3
this.name = imgstr;
imgStr aun se utiliza unas cuantas veces. Comprobamos las lineas 53-59. Aqui
se establece la propiedad strucutre:
this.structure =
'<TABLE WIDTH=500 CELLPADDING=lO><TR><TD WIDTH=60% VALIGN=TOP>' +
'<IMG SRC=' + imgPath + imgStr + '.gif></TD>' +
'<TD WIDTH=40% VALIGN=TOP><H2>Common Name:</H2><H2><1>'+
camelCap(imgStr) + '</I></H2><H3>Scientific Name: < / H 3 > < H 3 > < 1 > '+
scientific + ' < / I > < / H 3 > '+ '<B>Abstract:</B><BR>'+ copy +
'</TD></TR></TABLE>';
<IMG SRC='images/pig.gif'>
camelCap(imgStr)
function genScreen0 {
var menuStr = ' I ;
'out.gif"BORDER=O></A><BR>';
1
Al actuar sobre todos 10s elementos del array slideshow, la creacion de cada
capa se facilita mucho con la funcion genLayer ( ) . Veamoslo con detalle:
Pasa como argument0 una buena cantidad de valores. En la tabla 3.2 podemos
ver a cada uno de ellos.
Tabla 3.2. Argumentos para genLayer()
Valor Descripcion
'slide' + i Crea un nombre unico (pero indexado) para
cada una de las diapositivas, algo asi como
slide0, slidel, etc.
sWidPos La distancia en pixeles que separa el lado
izquierdo de la ventana y la diapositiva.
sHgtPos La distancia en pixeles que separa la parte
superior de la ventana y la diapositiva.
dWidLyr h c h o predeterminado de la diapositiva, en
este caso 450.
dHgtPos Alto predeterminado de la diapositiva, en
este caso 450.
( i == 0 ? true : false) Determina si la diapositiva aparecera en
pantalla (true)o no (false).Al principio,
todas las diapositivas estaran ocultas, menos
la primera. Esto ocurre cuando i = 0.
s1ideShow[ i] . structure Contenido de la diapositiva, que incluye
texto y grafico, incluidos en una tabla.
Procede del constructor de la diapositiva.
Diapositivas interactivas 119
Ya lo vimos en la linea 1 10, per0 entonces la variable rnenustr se inicio con una
cadena vacia. Ahora esta cadena contendra codigo HTML que se encargara de
mostrar una imagen detras de otra. En la figura 3 . 2 podemos ver su resultado.
Para cada capa, rnenuStr sera igual a si mismo y a la imagen asociada con la dia-
positiva. Antes de adentrarnos con las dobles comillas, vamos a ver las necesi-
dades de cada par de imagenes.
Como si onMouseOver no tuviese bastante que hacer, aun tendremos que aiia-
dir mas codigo para la funcion imageswap ( ) . Esta funcion controla la secuen-
cia de imagenes. Como tambien veremos mas adelante, bastara con que
recordemos que el codigo JavaScript tiene tres valores que se han entregado con
el metodo slideshow[ i I .name,el valor de i el booleano true.
El tercer elemento tiene 10s mismos requisitos que orzMouseOver, con la excep-
cion de que no se efectuara ninguna llamada a hidestatus ( ) porque ya se ha-
bra ocultado el contenido de la barra de estado y el ultimo c6digo que se ha
pasado a imageswap es el booleano false (en vez de true).
El cuarto elemento es bastante sencillo. Unicamente tendremos que aiiadir
onClick="false".De esta forma se cancela cualquier clic que pudiese hacer el
usuario.
Y 10s requisitos del quinto elemento se satisfaran con este codigo:
He dejado la llamada para el final porque las otras dos capas de navegacion
que se crean se colocan encima del menu de la diapositiva y creo que tiene mas
sentido generarlos en este orden. Observese que he utilizado la etiqueta < D I V >
con el atributo I D con valor menuconstraint.De esta forma nos aseguramos
que la diapositiva tendra una altura de 800 pixeles.
Necesitaremos hacer dos llamadas a genLayer() para completar la composicion
de la diapositiva. Una es para mostrar la imagen vinculada con la que se inicia-
ra y finalizara la propiedad de representacion automatica. La otra es para la
Diapositivas interactivas 121
imagen vinculada que muestra y oculta el menu que contiene las flechas que
permiten avanzar o retroceder. La creacion de la capa para la imagen vinculada
a la ejecucion automatica no tiene mucho misterio. Miremos las lineas 122-126:
El codigo para cada imagen sera muy similar. Ya lo vimos con las imagenes
vinculadas. De hecho, las flechas son imagenes vinculadas pero tienen el evento
onMouseOver condicionado a la llamada a c h a n g e s l i d e ( ) . Si se pasa el valor -1,
la aplicacion mostrara la dispositiva anterior a la que aparece en pantalla. Per0 si
pasa el valor 1, mostrara la siguiente diapositiva. En breve veremos la funcion
c h a n g e s l i d e ( ) . L a imagen vinculada <Guide> mostrara u ocultara el menu
de la diapositiva. El encargado de controlar esta situacion SeramenuManager ( ) .
Antes de entregar el resto del codigo a g e n s c r e e n ( ) , conviene destacar que la
llamada se hace desde entro de la etiqueta <BODY> antes de que se cargue la pa-
gina. MSIE no puede crear las capas despuCs de la carga del documento, por lo
que tendremos que hacerlo antes. Este es el contenido de las lineas 215-219:
<SCRIPT LANGUAGE="JavaScript1.2">
<!--
genScreen ( 1 ;
//-->
</SCRIPT>
122 DiaDositivas interactivas
Elementos de la diapositiva
Ya nos hemos encontrado en mas de una ocasion con el array slideshow. Cada
uno de sus elementos contiene un bloque de propiedades de un objeto slide. Este
es su codigo, el encargado de mostrar las diapositivas de 10 animales:
Compara 10s valores que se le pasa en cada llamada a1 constructor slide con 10s
argumentos que espera recibir. El primer0 es el nombre del animal (y la ima-
gen); el siguiente es el nombre cientifico. Y cada uno lleva asociado un texto
descriptivo, La linea 85 tiene codigo HTML que incluye algo de texto. No hay
ninguna raz6n por la que no nos podamos construir el contenido de la diaposi-
tiva basandonos en este concepto, incluso definiendo las capas de las propias
diapositivas.
Si la lista es muy larga, podemos colocarla dentro de un archivo de codigo fuen-
te en JavaScript para despejar de alguna forma el codigo de la aplicacion. En este
caso, como unicamente tenemos diez elementos, lo hemos dejado asi.
preloadlmages()
Esta funcion se encarga de cargar la imagen antes de que sea necesaria. Su co-
dig0 se encuentra en las lineas 64-73:
function imagePreLoad(imgStr) {
img [ img . length] = new Image ( ) ;
img[img.length - 11.src = imgPath + imgStr + ' . g i f t ;
imgOut[imgOut.length] = new I m a g e O ;
imgOut[imgOut.length - 11.src = imgPath + imgStr + 'out.gif';
imgOver[imgOver.lengthl = new I m a g e O ;
imgOver[imgOver.length - 11.src = imgPath + imgStr + 'over.gif';
}
Esta funcion crea u n objeto Image nuevo y carga las tres fuentes a las que hace
referencia a la vez. De esta forrna se aumenta el tiempo de carga de la aplica-
cion, per0 se evita que 10s usuarios tengan que esperar a que se carguen las ima-
genes cuando saltan de una ficha a otra.
Las variables irngPath e imgStr se concatenan junto con gif, out.gif y over.gif,
respectivamente, para hacer las asociaciones pertinentes a cada diapositiva. Por
ejemplo, a la diapositiva de la vaca (cow) se le asociaran las imagenes cow.gif,
cowout.gif y cowover.gif,
imageswap()
Esta funcion se encarga de la secuenciacion de las imagenes si el usuario decide
pasarlas manualmente colocando el punter0 sobre el nombre de alguno de 10s
animales de la lista o cuando es la aplicacion quien se encarga de hacerlo por tra-
bajar en modo automatico. El c6digo lo tenernos en las lineas 179-182:
Gran parte de 10s scipt encargados de pasar las imagenes trabajan con dos fun-
ciones independientes: una para onMouseOver y otra para onMouseOut. En cual-
quier caso, podemos combinarlas en una unica funcion.
Los argumentos imageprefix, imagelndex e isOver representan la cadena base
que se utiliza para nombrar a la imagen (imgStr).El indice de la imagen deseada
(el valor de i del bucle for que se encuentra en la funcion genscreen ( ) ) y un
valor booleano se utilizaran para indicar cuando se utilizaran las imagenes que
se encuentran dentro de 10s array imgOver o de imgOut.
124 Diapositivas interactivas
imageSwap('bird', 0, true):
Una vez que se llama a la funcion, entonces podremos ver la imagen en la pan-
talla. Como isOver es t r u e , entonces:
Funciones de navegacion
La funcion de la diapositiva se ha encargado de crear su contenido y de contro-
lar como aparecerBn en la pantalla. Las funciones de la imagen permiten que se
carguen antes de que se necesiten y la ejecucion automatica. Ahora vamos a ver
como se convierten todos estos elementos en una diapositiva. Es decir, las fun-
ciones de navegacion.
refslide(), hideslide(), showslide() y menuManager()
Ya hemos creado las diapositivas y se han cargado las imagenes correspondien-
tes. Ahora queremos hacer cosas con ellas, es decir, mostrar en pantalla la que
queramos y ocultar el resto. Antes de manipularlas, tendremos que hacer una
referencia. Es muy sencillo, iverdad?. La referencia la haremos basandonos en el
nombre de la capa. La verdad es que si y no. Tendremos que utilizar el nombre
de la capa, pero no olvidemos que MSIE y Navigator usan distintos modelos de
objetos. La funcion r e f s l i d e ( ) se hara cargo de ello. L a tenemos en las lineas
146-149:
function refSlide(name1 {
if ( N N ) ( return document.layers[namel; 1
else { return eval('document.al1.' + name + '.style'); 1
1
referencia utilizando eval ( ' document. all. ' + name + style ' 1. hi, po-
dremos modificar la visibilidad de la capa, sin que importe el explorador que uti-
licemos. Luego, no ha de sorprendernos encontrarnos ambas funciones en las
lineas 151-157.
No solo es asi de sencillo, sino que podremos acceder a estos miembros en el
momento en que queramos:
function hideSlide(name1 {
refSlide(name).visibility = hideName;
>
function showSlide(name) {
refSlide(name).visibility = showName;
I
una dkpositiva determinada, tendremos que usar la funci6n ref Slide ( ) para
establecer una referencia para ella y configurar el valor de la propiedad visibility
del objeto devuelto a hidel\rarne.El valor de hideName, si recordamos, lo vimos en
la linea 22, era hide o hidden, dependiendo del explorador que utilizase el usua-
rio. El mismo cddigo se utiliza para mostrar diapositivas, con la excepcion de que
la propiedad visibility tendra que ser showName, obviamente, dependiendo del
explorador utilizado (linea 23).
Las funciones hideslide ( ) y showslide ( ) se utilizan para ocultar y mostrar
las diapositivas y el menu. No se las llamara directamente, sino que se utilizara
la funci6n menuManager ( ) :
function menuManager0 {
if (isvis) { hideSlide('menu'); 1
else ( showSlide('menu'); 1
isvis = !isVis;
1
changeslide()
Ahora que podemos establecer referencias correctamente a las diapositivas,
independientemente del explorador que utilice el usuario para ejecutar la aplica-
cibn, necesitaremos una funcion que cambie la diapositiva que se encuentra en
la pantalla por la siguiente. En realidad tenemos dos funciones: changeslide (
y setslide ( ) .
El cambio de una dispositiva por otra es un proceso que se desarrolla en tres
pasos:
Los pasos 1 y 3, a estas alturas, nos pareceran bastante sencillos. Per0 el segun-
do es mas complicado de lo que puede parecer. Hay dos situaciones en las cuales
podremos cambiar las diapositivas. La primera ocurrira cuando queramos cam-
biar las dispositivas una a una, hacia delante o hacia atras, siguiendo una se-
cuencia. Esta situacion nos la encontramos cuando utilizamos las flechas del
menu. La segunda situacion nos la encontraremos cuando trabajemos con el mo-
do automatico de la aplicacion. La funci6n changeslide ( ) se encargara de am-
bos supuestos. veamos el contenido de las lineas 165-1 70:
DiaDositivas interactivas 127
function changeSlide(0ffset) {
hideSlide('s1ide' + curslide);
curslide = (curslide + offset < 0 ? slideShow.length - 1 :
(curslide + offset == slideShow.length ? 0 : curslide + offset));
showSlide('s1ide' + curslide);
}
curslide es 0 (linea 13). Como este numero hace referencia a la dispositiva que se
encuentra en la pantalla, la funcion hideslide ( ) ocultara slide0, que es la dia-
positiva del pajaro. Bien. iQuC diapositiva se mostrara a continuacion?
Recordemos que changeslide ( espera el parametro onset, el cual podra ser
16 - 1.El primer valor hace que se muestre la siguiente diapositiva, mientras que
el segundo mostrara la anterior a la que se encuentra en pantalla. ComocurSZide
es un entero que representa el indice a1 que pertenece la imagen de la pantalla, a1
aiiadir 1 , su valor cambiara a 1, luego a 2 , etc. Como - 1 mostrara la diapositiva
anterior a la que se encuentra en la pantalla, si Csta fuese la numero 3, pasarA a
mostrar la numero 2 y luego la 1, etc.
Todo ira bien, hasta el momento en que intentemos acceder a ' slide ' + -1
o ' slide +slideshow.length. Esta dispositiva no existe, por lo que nos po-
I
demos encontrar con una pantalla en blanco o con u n error de sintaxis. Enton-
ces, ic6mo podemos evitar que curslide sea menor que cero?
La respuesta la tenemos en las lineas 167-168:
function setSlide(ref) I
if (touron) { return; 1
hideSlide('s1ide' + curslide);
curslide = ref:
showSlide('s1ide' + curslide);
}
function autopilot0 {
if (touron) {
clearInterval(auto);
imageSwap(slideShow[curSlidel .name, curslide, false);
1
else {
auto = setInterval('automate()' , showspeed);
imageSwap(slideShow[curSlidel .name, curslide, true);
showSlide('menu');
visible = true;
1
tourOn = !touron:
1
Diapositivas interactivas 129
automate()
automate ( ) es una pequeiia funcion que se encarga de mostrar las diapositivas,
para lo cual desarrolla tres operaciones:
1. Simula un evento onMouseOut que oculta la imagen que se encuentra en la
pantalla. Para ello llama a imageswap ( .
2. Avanza a la siguiente diapositiva con una llamada a changeslide ( ) .
3. Simula un evento onMouseOver para activar la siguiente diapositiva del
menu para mostrarla en la pantalla. Utiliza una llamada a imageswap ( ) .
Aqui tenemos las lineas 200-204:
function automate ( ) {
imageSwap(slideShow[curSlidel .name, curslide, false);
changeSlide(1);
imageSwap(slideShow[curSlidel .name, curslide, true);
1
Posibles ampliaciones
Al igual que ocurre con casi todas las aplicaciones que utilizan DHTML, pode-
mos utilizar esta aplicaci6n para desarrollar un sin fin de tareas en las que ten-
ga que mostrar diapositivas. Vamos a ver unas cuantas.
Diapositivas interactivas 131
function randomslide0 I
var randIdx = Math.floor(Math.rand0 slideShow.length);
setSlide(rand1dx);
1
function automate() {
imageSwap(slideShow[curSlidel.name, curslide, false);
randomslide ( ) ;
imageSwap(slideShow[curSlidel.name, curslide, true);
1
Number of results 8
Figura 4.2. Image Surfer nos muestra 10s dibujos que tiene en su base de datos
y que estkn asociados con el tkrmino "andromeda"
lnterfaz para un motor de busqueda multiple 135
Analisis de la sintaxis
En esta aplicacih intervendran dos archivos: index.htrnZ y rnuZti.htrnZ. El con-
tenido del primero lottenemos en el ejemplo 4.1. Utiliza cuadros anidados para
conseguir el efecto del borde.
Ejemplo 4.1.index.htm1
1 <HTML>
2 <HEAD>
3 <TITLE>Multi-Search Engine Interface Site</TITLE>
4 <SCRIPT LANGUAGE="JavaScriptl.2">
5 <!--
6 var black = '<BODY BGCOLOR=BLACK></BODY>';
I var white = '<BODY BGCOLOR=WHITE></BODY>';
8 //-->
9 </SCRIPT>
10 < /HEAD>
11 <FRAMESET ROWS="15,* , 50" FRAMEBORDER=O BORDER=O>
12 <FRAME SRC="javascript: parent .black; " SCROLLING=NO>
13 <FRAMESET COLS="15,*, 15" FRAMEBORDER=O BORDER=O>
14 <FRAME SRC="javascript: parent.black;"SCROLLING=NO>
15 <FRAME SRC="javascript: parent.white;">
16 <FRAME SRC="javascript: parent.black;"
17 SCROLLING=NO>
18 < /FRAMESET>
19 <FRAME SRC="multi.html" SCROLLING=NO>
20 < /FRAMESET>
21 < / HTML>
Las dos variables en JavaScript, black y white que se encuentran en las lineas 6
y 7, se evaluan como cadenas HTML dentro del atributo SRC de 10s marcos de la
linea 12 y 14-16 . Ya hemos visto en el capitulo 2 como se hace. Los unicos mar-
cos que ven algun tip0 de acci6n real son frames [ 2 ], que muestra 10s resulta-
dos, y frames [ 4 I , donde e s t h n 10s motores de busqueda. El resto unicamente
se utilizan meramente para el espect8culo. Vamos a ver el contenido del archivo
rnuZti.htrnZ que se encuentra dentro del ejemplo 4.2.
136 lnterfaz para un motor de busqueda multiple
61 new Array('MovieFinder.com',
62 'http://www.moviefinder.com/search/results/1,10,,00.html?'+
63 'simple=true&type=movie&mpos=beqin&spat=',
64 8http://www.moviefinder.com/') I
73 'http://xlink.zdnet.com/cqi-bin/texis/xlink/xlink
search.html? ' +
74 'Utext=',
75 !http:l/www.zdnet.com/'),
76 new Array('Biography.com',
17 !http://www.bioqraphy.com/cgi-bin
biomain.cgi?search=FIND&field=*,
78 'http://www.biography.com/'),
79 new Array('Entertainment Weekly',
80 'http://cgi.pathfinder.com/cqi-bin/ew/cg
pshell?venue=pathfinder&q=',
81 thttp://www.entertainmentweekly.com/'),
82 new Array('SavvySearch',
83 'http://numan.cs.colostate.edu:l969/nph-search?'+
84 'classic=on&Boolean=OR&Hits=lO&Mode=MakePlan&df=normal'
+
85 '&AutoStep=on&KW=',
86 ,http://www.savvySearch.com/'),
87 new Array('Disc0very Online',
88 !http://www.discovery.comlcgi-bin/searcher/-?'i
89 'output=title&exclude=/search&search=',
90 'http://www.discovery.com/'),
91 new Array('Borders.com',
92 +
'http://www.borders.com:8080/fcgi-bin/db2www/search/'
138 lnterfaz Dara un motor de blisaueda mljltide
93 'search.d2w/QResults?doingQuickSearch=l&srchPage=QResults~+
94 '&mediaType=Book&keyord=',
95 ~http://www.borders.com/'),
96 new Array( 'Life Magazine',
97 'http://cgi.pathfinder.com/cgi-bin/life/cg/pshell?' +
98 'venue=life&pg=q&date=all&x=15&y=l6&q=',
99 'http://www.life.com/')
100 );
101
102 engines = engines.sort ( ) ;
103
104 function imagePreLoad(imgName, idx) {
105 for(var j = 0; j < arrayHandles.length; j++) {
106 eval (arrayHandles[ j I + " [ " + idx + " I = new Image ( ) ) ;
"
107 eval (arrayHandles[j] + " [ " + idx + " I . src = ' " + imgPath +
108 imgName + arrayHandles[jI + " . jpg'" ) ;
109 }
110 1
111
112 function enginelinkso
113 genLayer('sliderule', left - 20, top + 2 , 25, engHgt, true,
114 ' < A HREF="javascript: changeSlide(1); " ' +
115 'onMouseOver="hideStatus();return true;">'+
116 '<IMG SRC="' + imgPath + 'ahead.gif" BORDER=O></A><BR>' +
117 '<A HREF="javascript: changeslide(-1); " ' +
118 'onMouseOver="hideStatus( ) ; return true;" > ' +
119 QIMG SRC="' + imgPath + 'back.gif" BORDER=O></A>');
120 lyrCount = Math.cei1
121 (engines.length / perlyr);
122 for (var i = 0; i < lyrcount; i++) {
123 var engLinkStr = '<TABLE BORDER=O CELLPADDING=O
CELLSPACING=O><TR>';
124 for (var j = 0; j < perLyr; j++) {
125 var imgIdx = (i * perLyr) + j;
126 if (imgIdx == engines.length) { break; 1
127 var imgName = nameFormat(engines[imgIdxl[OI);
128 imagePreLoad(imgName, imgIdx);
129 engLinkStr += '<TD><A HREF="javascript: ' +
130 'callSearch(document.forms[Ol.elements[Ol .value, ' +
131 imgIdx + ' ) ; " onMouseOver="hideStatus(); imageswap(\" +
132 imgName + ' \ ' , ' + imgIdx + ' , 1); return true" ' +
133 'onMouseOut="imageSwap(\" + imgName + ' \ ' , ' + imgIdx +
134 I , 0) ;"><IMGNAME="' + imgName + ' ' I SRC="' + imgPath +
135 imgName + 'out.jpg' + "' BORDER=O></A></TD>';
13 6 }
137 engLinkStr += '</TR></TABLE>';
138 genLayer('s1ide' + i, left, top, engwdh, engHgt, false,
engLinkStr);
139 I
140 I
141
lnterfaz para un motor de bifsqueda mifltiple 139
191 escape(searchTxt);
192 I
193
194
195 function hidestatus() { window.status = " ; 1
196
197 / / - - >
198 </SCRIPT>
199
200 </HEAD>
201 <BODY BGCOLOR="BLACK" onLoad="showSlide ( slide0 ' ) ;" >
202 <SCRIPT LANGUAGE="JavaScriptl.2">
203 < ! - -
204 engineLinks ( ) ;
205 / / - - >
206 </SCRIPT>
207 <FORM onSubmit="return false; " >
208 <TABLE CELLPADDING=O>
208 <TR>
210 <TD>
211 <FONT FACE=Arial>
212 <IMG SRC="images/searchtext.jpg">
213 </TD>
214 <TD>
215 <INPUT TYPE=TEXT SIZE=25>
216 < / TD>
217 </TR>
218 </TABLE>
219 </FORM>
220 </BODY>
221 < / HTML>
Mas de 200 lineas de codigo. Per0 realmente ya hemos visto gran parte. No va
a ser tan terrible como parece. Empecemos con la linea 7.
Algo de memoria
Vamos a darnos una vuelta por la memoria RAM.Segun analicemos las varia-
bles que aparecen a continuacion, nos encontraremos con algunas novedades,
per0 el funcionamiento de la mayor parte coincide con el visto en el capitulo 3.
Tenemos las siguientes variables N N , curSZiede, hideName, showName, imagepath
y sldx:
Lineas 163-177:
function refSlide(name) {
if ( N N ) { return document. layers [name]; )
else { return eval('document.al1.' + name + '.style'); 1
1
function changeSlide(0ffset) (
hideSlide('s1ide' + curslide);
curslide = (curslide + offset < 0 ? slideShow.length - 1 :
(curslide + offset == slideShow.length ? 0 : curslide + offset));
showslide( 'slide' + curslide) ;
1
que tendriamos 20 6 40 lineas. Si alguna vez tenemos que hacer algun cambio,
nos encontraremos en medio de un problema, independientemente de la canti-
dad de pares de imagenes que tengamos. Necesitaremos tres cosas:
Para el paso 1 , esta aplicacion utilizara dos arrays. Uno de ellos se llamara out
y contendra objetos Image de esas imagenes que se utilizaran en el momento en
que el cursor abandone un vinculo. El otro se llamar6 over y contendra objetos
Image para 10s casos en 10s que el cursor se encuentre sobre un vinculo. Estas va-
riables se representaran en un array de cadenas llamada arrayHandles, que se
encuentran en la linea 20.
Sin embargo, estas cuatro lineas de codigo representan precisamente aquello que
quiero evitar una y otra vez. Siempre que necesitamos un nuevo par de image-
nes, podre llamar a la funci6n preLoadImages( ) . Y ademas funciona mucho
mejor.
engine Links()
La funcion engineLinks ( ) se parece a la funcion genScreen ( ) que vimos en
el capitulo tercero porque es la que se encargara de la creacion de las capas. Aun-
que tambitn tiene sus diferencias. Veamos a continuacion el contenido de las li-
neas 112-140.
Administracion de capas
Lo primer0 que hace la funcion es generar la capa que contiene 10s vinculos de
navegacion:
Para que ocurra esto, bastara con una sencilla llamada a genLayer ( ) . No tie-
ne ningun misterio. La capa contendra dos imagenes vinculadas: una flecha de
avance y otra de retroceso. Observese que 10s valores de 10s pixeles izquierdo y
superior que se pasan, son relativos a las posiciones izquierda y superior de las
capas de 10s motores que crearemos en u n momento.
A continuacion, la variable ZyrCount determina el numero de capas de 10s boto-
nes de 10s motores de bdsqueda que se han de crear. Obviamente, dependera del
numero de botones que tiene cada capa y del numero de motores que hemos
distribuido en el array engines. Es muy sencillo. Dividimos el numero de moto-
res de busqueda (engines.length) por el numero de motores que vayamos a
mostrar por capa (perLyr).Si el resto es distinto de cero, entonces necesitaremos
una capa m&.
lnterfaz para un motor de busqueda multiple 147
la linea 123, se inicia una tabla que englobara todas las imagenes. Un bucle for
anidado repetira perLynr para crear las celdas de la tabla, dentro de las cuales ira
colocando las imagenes.
Para cada repeticion perlyr, a la variable local irngIdx se le asignara el valor ( i *
perLyr ) + j . Esta expresion no es mas que un entero cuyo valor inicial sera
0 y que se ira incrementando una unidad con cada repeticion. irngldx se utiliza-
ra para identificar el prefijo de las imagenes (que se corresponde con el nornbre
del motor de busqueda del elemento 0) y proceder con la carga previa de las ima-
genes de la que ya hemos hablado. En la tabla 4.1 tenemos un ejemplo de la mul-
tiplicacion que tiene lugar cuando el valor de perLyr es 4.
Como el valor de imgldx se va aumentando con cada repeticion, una vez que
alcance el valor de engines. length, no habra mas motores de busqueda, con
lo que la funcion interrumpira el buclefor.
function nameFormat(str1 I
var tempArray = str.split(' ' 1 ;
return tempArray.join(").tOLOwerCase~);
Para eliminar 10s espacios en blanco se divide la cadena que se entrega entre 10s
elementos del array y luego se vuelve a unir. Ahora imgName tiene el prefijo de
las imagenes, en minusculas y sin espacios en blanco. Esta listo para pasarselo,
junto con imgIdx a imagepreload ( ) en la linea 128.
Construir el vinculo
Ha llegado la hora de crear la imagen que se vinculara a1 codigo correspon-
diente a 10s motores de busqueda. Lo tenemos en las lineas 129-135:
"' BORDER=O></A></TD>';
imageswap()
Ya lo hemos visto en el tercer capitulo, per0 esta version es diferente. Veamos el
contenido de las lineas 179-1 82:
callsearch()
Cuando ya se tiene el formulario HTML y las capas en su sitio, el usuario uni-
camente tendra que introducir el texto de busqueda y hacer clic en el motor de
busqueda con el que quiera trabajar. Cuando hace clic en la imagen correspon-
diente a dicho buscador, la aplicacion llamara a la funci6n callsearch ( ) . Te-
nemos su codigo en las lineas 184-193:
Es posible que se pregunte de donde he sacado las cadenas tan largas del ele-
mento 1 de cada array de engines.
He comprobado el codigo fuente de cada pagina de busqueda y he creado una
cadena de busqueda basada en el formulario HTML usado para enviar texto.
Empezamos con un ejemplo facil. Musicsearch.com solo tiene un campo de bus-
queda. El atributo ACTION del formulario http://www.musicsearch.com/global/
searcg.cgi.El nombre del campo es QUERY.Asi, la cadena de busqueda debe ser:
http://www.musicsearch.com/global/search/search.cgi?QUERY=
i
escape(searchTxt);
lnterfaz para un motor de bljsqueda multiple 153
El valor de Boolean sera OR, el de Hits sera 10, el de df normal y el del campo de
texto KW, escape (searchTxt) . No me he inventado ningun valor. Los he sa-
cad0 de las listas de selection o de 10s posibles valores de 10s botones de opcion.
Es decir, son valores perfectamente validos en el codigo HTML.
El formulario tambitn contiende dos campos ocultos. Uno tiene el nombreMode
y el otro Autostep. El campo Mode HIDDEN tiene el valor Makeplan. El campo
Autostep HIDDEN tiene el valor on. La verdad es que no tengo muy Clara su res-
pectiva finalidad, per0 en cualquier caso no importa. Todo lo que tenemos que
hacer es incluirlos a la cadena de busqueda. Enviamos una peticion a Savvysearch
y solicitamos el siguiente URL:
http://numan.cs.colostate.edu:l969/nph-search? +
classic=on&Boolean=OR&Hits=lO&Mode=MakePlan&df=normal&AutoStep=on&KW=
+ escape (searchTxt)
tendra control sobre las busquedas. L o unico que puede hacer es introducir el
texto de la consulta. Podemos codificarlo de tal forma que 10s usuarios puedan
intervenir en propiedades como el ndmero de resultados que apareceran por
pagina, la cantidad de information que se mostrara en cada uno de ellos o la
posibilidad de trabajar con booleanos como AND, OR, LIKE, NOT LIKE. En esta
seccion veremos un ejemplo basado en HotBot.
Posiblemente, la forma mas sencilla de aumentar la funcionalidad es aumentar
el numero de resultados por pagina. Necesitaremos el par nombre-valor asocia-
do con 10s resultados de las paginas de cada buscador. En la tabla 4.2 tenemos
una serie de valores posibles para unos cuantos motores de busqueda.
El nombre de 10s campos 10s he obtenido del c6digo de las paginas de busqueda
de 10s respectivos motores. Algunos campos unicamente aparecen con las opcio-
nes avanzadas, por lo que 10s U R L del array engines no funcionaran. Tampoco
hay que olvidar que es posible que no se pueda ajustar el numero de resultados.
Los desarrolladores de 10s motores de busqueda pueden trabajar con un valor fijo.
Si en la pagina de busqueda no encontramos una opci6n con la que modificar el
numero de resultados de la pagina, quiza podamos ponernos en contact0 con la
organizacion y preguntar si se puede modificar esta opci6n. Si no es asi, unica-
mente se podra trabajar con el valor predeterminado de ciertos buscadores.
Tambitn nos encontramos con que 10s posibles valores varian de un motor de
busqueda a otro. Tendremos que incluir algo de c6digo para compensar este efec-
to. No es muy complicado. Utilizaremos el siguiente procedimiento para agregar
una lista de selecci6n a la aplicacion. A continuaci6n la utilizaremos como guia
para incluir otras propiedades de control.
Paso 2
Cada ejemplo de new Array() del array engines define un motor de busqueda
con tres elementos. El elemento 0 es el nombre del motor de busqueda; el ele-
mento 1 es la cadena de la solicitud; y el elemento 2 es la pagina principal del
buscador. Aqui volvemos a tener a HotBot:
n e w Array( 'HotBot I ,
'http://www.hotbot.com/?MT=',
~http://WWW.hotbot.com/')
Si uno o mas buscadores no trabajan con el valor que hemos determinado (por
lo tanto, carecen de un par nombre-valor), el valor del elemento 3 serh nulo.
156 lnterfaz para un motor de bhqueda mdtiple
Paso 3
Una vez que hemos identificado el nombre, afiadiremos otro array que contie-
ne todos 10s valores con 10s que se puede trabajar. De esta forma, definiremos un
nuevo array en el elemento 4. Si volvemos a consultar la tabla 4.2, veremos que
el aspect0 del registro de HotBot sera el siguiente:
Paso 4
Este paso unicamente se aplicara si la cadena predeterminada del elemento 2
contiene el par nombre-valor de 10s resultados. Esta sera la cadena de HotBot
del elemento 2:
http://www.hotbot.com/?MT=
Como DC no aparece ahi, podemos saltarnos este paso. Per0 como ejemplo, el
buscador de Scientific American contiene el par nombre-valor, que es docs = 1 0 0.
Veamos:
http://www.sciam.com/cgi-bin/search.cgi?'+
'searchby=strict&groupby=confidence&docs=lOO&query=
parent.frames[2].location.href = engines[idxI[21 +
escape(searchTxt);
>
else {
parent.frames[2].location.href = engines[idxl [ll +
escape(searchTxt);
1
I
else {
if(engines[idxl [31 ! = null) {
for (var i = 0; i < engines[idx][4l.length; i++) {
var selRef = parent.frames[4].document.forms[0l.docs;
if (selRef.options[selRef.selectedIndex].value =
engines[idxl [4][il .tostring()) (
parent.frames[2].location.href = engines[idxl [ll +
escape(searchTxt) + ' t i ' + engines[idx1[31 + +
I = '
parent.frames[2].location.href = engines[idxl[ll +
escape(searchTxt) + ' & ' + engines[idx1[31 + +I = '
Todas las aplicaciones que hemos visto se han diseiiado para una persona: el
usuario, esa persona que navega por Internet, llega a nuestras paginas Web, re-
visa el contenido, compra nuestros productos y descarga software. Esta aplica-
cion rompera con todos 10s moldes. Se ha diseiiado para la otra cara de la moneda:
el diseiiador.
Aunque DHTML ha mejorado considerablemente el resultado de 10s eventos
que se desarrollan en la Web cuando colocamos el cursor del raton sobre alguna
flecha, cuadro, b o t h u hoja de estilo, la secuencia de imagenes es una de las
ttcnicas que mas se utiliza en la Web.
Generar un codigo en JavaScript que se encargue de desarrollar este cambio de
imagenes no es muy complicado. Per0 seguro que nos complicaremos menos la
vida si creamos una aplicacion que se encargue de ello. De esta forma, como
programadores que somos, todo lo que tendremos que hacer sera reutilizar el
codigo siempre que lo necesitemos. En la figura 5.1 se puede ver la primera pan-
talla de nuestra aplicacion: ImageMachine.
El manejo de la aplicacion es muy sencillo. Bastar6 con que tomemos un par de
decisiones sobre las imagenes. Como nos indica la figura 5.1:
_ .. . .
+ . - ? .
Image Machine dynamically generater JaraScript code and HTML needed to create image ro110vers
Heres all you need t o get $laded
..
the width and height m pixels
the image URLr
Image Machine then generates cut and paste code you can easily drop into y o ~ r w e bpages You
ran also see *hat the page look$ like before you decide to keep the code
Cul mdpesle (he code belowinlo en HTML nle Jhe blue code repiesenls informslian you prowided
Una de las propiedades mas interesantes del c6digo que se genera con esta apli-
cacion es que reduce efectividad de acuerdo con la capacidad que tiene el explo-
rador Web utilizado para trabajar con JavaScript. Es decir, 10s exploradores que
trabajen con la versi6n 1.2 de JavaScript utilizaran i d o w e o v e r , onMouseOut y
onMouseDown, mientras que 10s exploradores compatibles con la versi6n 1.1 de
JavaScript unicamente trabajaran con onMouseOver y onMouseOut. Los explora-
dores compatibles con JavaScript 1.O se limitaran a mostrar el texto relaciona-
do en la barra de estado.
iY quk tal se lleva este sistema de trabajo con el ancho de banda? S610 se des-
cargaran las imageries que se vayan a utilizar. De hecho, si el explorador no pue-
de trabajar con ellas, no las cargara. Asi, 10s exploradores compatibles con 1.1
no descargaran la imagen relacionada con el evento onMouseDown. Y 10s com-
patibles con JavaScript 1.O no descargaran ninguna.
Figura 5.4.A travks de 10s botones "Preview"y Change Info" se accede a otras
opciones
Analisis de la sintaxis
Antes de entrar a ver el codigo, debemos hacernos una idea visual de c6mo fun-
ciona el programa. En la figura 5.5 vemos el grafico de flujo basico, de principio
a fin. Empezaremos creando el formulario de la imagen y configurando 10s as-
pectos de cada secuencia. Luego, avanzaremos y retrocederemos para acceder a
la vista previa, efectuar modificaciones y generar el c6digo. Cuando tengamos
el codigo que realmente nos gusta, podremos copiarlo donde queramos.
164 ImageMachine
Generacibn
del fomrulario
de la imagen
II
hsercibn de /as Mas
de la imagen, HREF
y text0 de la barn
de estado
4 Borrar
previsualizar
Generar
Guardar
4
17 1
18 document.write("<SELECTNAME=" + name + " > " + optStr +
"</SELECT>") ;
19 }
20
21 function captureDefaultProfile(form0bj) {
22 setArrays( ) ;
23 imgDefaults = formObj;
24 var imgQty = (imgDefaults.imgnumber.se1ectedIndex + 1);
25 var imgHeight = (imgDefaults.pxlheight.selectedIndex);
26 var imgWidth = (imgDefaults.pxlwidth.selectedIndex);
27 var imgBorder = (imgDefaults.defbdr.selected1ndex);
28 for (var i = 0; i < imgQty; i++) {
29 imgPrim[il = " ' I ;
31 imgDown[i] = "'I;
34 imgWdh[il = imgwidth;
35 imgHgt[i] = imgHeight;
166 ImageMachine
36 imgBdr[il = imgBorder;
37 }
38 generateEntryForm0;
39 }
40
41 function setArrays0 {
41 imgPrim = new Array
43 imgRoll = new Array
44 imgDown = new Array
45 imgLink = new Array
46 imgText = new Array
47 imgwdh = new Array
48 imgHgt = new Array
49
50
51
52
53 function generateEntryForm0 {
54 with(parent.frames[l].document) {
55 open ( ) ;
56 writeln("<HTML><BODY BGCOLOR=FFFFEE><FONTFACE=Arial SIZE=2>"
57 + "<BLOCKQUOTE>Chooseor enter the paths of all images in
58 the '' + "columns below. Add the link path (e.g., <FONT
FACE=Courier> " +
59 "webgage.html</FONT>)or script text (e.g., <FONT
FACE=Courier>" +
60 "javascript:</FONT>)for each HREF attribute, and enter
any
'I +
61 "message you want to display in the status bar during the ''
62 + "<FONT FACE=Courier>MouseOver</FONT> event. Then choose ''
63 + "<B>Generate</B> to get your code, or <B>Preview</B> to
see the " +
64 "code in action.</BLOCKQUOTE><FORM NAME='imgProfile' +
65 "onSubmit='return false;'><CENTER><TABLEBORDER=O
ALIGN=CENTER
I' +
66 "CELLSPACING=5 CELLPADDING=5><TH ALIGN=LEFT><FONT
FACE=Arial>#" +
67 "<TH ALIGN=LEFT><FONT FACE=Arial>Primary Path" +
68 "<TH ALIGN=LEFT><FONT FACE=Arial>Rollover Path" +
69 (imgDefaults.mousedown.checked ? "<TH ALIGN=LEFT>" +
70 "<FONT FACE=Arial>MouseDown Path" : " " ) +
71 " < T R > < T D > < B R > < / T D > < / T R) >;"
72 1
73
74 for (i = 0 ; i < imgPrim.length; i++) {
75 with(parent.frames[ll.document) {
76 writeln( "<TR>" +
77 "<TD><FONT FACE=Arial SIZE=2><CENTER><B>"+ (i + 1) +
78 "</B></CENTER><TDVALIGN=BOTTOM><FONT FACE=Arial SIZE=2>" +
79 "<INPUT TYPE=FILE NAME='prim" + i + '' VALUE=''' +
imgPrim[il i
Irnage Mac hine 167
116 close ( ) ;
117 1
118
119
120 function imgValid8(imgTemplate,mimeType) I
121 for (var i = 0; i < imgPrim.length; i++) {
122 if (imgTemplate['prim'+ i] .value == II "I'
127 1
128 if (imgDefau1ts.mousedown.checked)I
129 if (imgTemplate['down' + i] .value == " " ) {
130 alert("Al1 images and HREF attributes must have URLs.");
131 return;
132 >
133 1
134 1
135 genJavaScript(imgTemplate, mimeType);
136 1
137
138 function genJavaScript(imgTemplate, mimeType) I
139 imageLinks = " ;
140
141 if (mimeType) (
142 It = "<";
143 gt = " > ; " ;
144 br = <BR> ;
'I #*
154 >
155
156 if(imgTemp1ate ! = null) {
157 setArrays( ) ;
158 for (var i = 0; i < (imgDefaults.imgnumber.selected1ndex +
1); i++) {
159 imgPrim[i] = purify(imgTemp1ate"prim' + i].value);
160 imgRoll[i] = p u r i f y ( i m g T e m p 1 a t e " s e c i ' + i].Value);
161 if (imgDefau1ts.mousedown.checked) I
162 imgDown[i] = purify(imgTemplate['down' + il .value);
163 >
164 imgLink[i] = purify(imgTemplate['href' + i1.value);
165 imgText[i] = purify(imgTemp1ate"stat' + i].value);
166 imgWdh[i] = purify(imgTemp1ate"wdh' + i1.value);
167 imgHgt[i] = purify(imgTemp1ate"hgt' + i].value);
168 imgBdr[i] = purify(imgTemp1ate"bdr' + il .value);
169 1
170 1
171
172 if (HTML) {
173 primJavascript = "<HTML><HEAD><TITLE>ImageMachine
Code</TITLE>" +
174 "</HEAD><BODY BGCOLOR=FFFFEE><FONT FACE=Arial>" +
175 "<I>Cut and paste the code below into an HTML file. The
blue " -I
IrnageMachine 169
214 "over.src = +
' * I
244 (imgDefaults.mousedown.checked?
245 br + nbsp + "onMouseDown=\"isDown=!isDown;
imageswap( switch" +
246 (j + 1) + 'down',true);\"" : " " ) +
" I ,
269 (imgDefau1ts.mousedown.checked ?
270 "if (!isDown) { " + br + nbsp + nbsp : " " ) +
271 "document[ imageName] . src = +
272 "eval(imageName + imagesuffix + \".src\"); " + br + nbsp +
216 (imgDefau1ts.mousedown.checked ? nbsp + " ) " + br + nbsp +
274 "else if (canClickDown) + br + {I'
286
287 S ecHTML = (HTML ? "<FONT COLOR=RED>" : " " ) +
288 It + <I> Image Code Ends</I> / / - - " + gt +
' I ! - -
299
300 agregate = primJavascript +
301 (imgDefau1ts.mousedown.checked ? scriptclose + secJavaScript
: " 8 9 ) +
318
319 </SCRIPT>
320 </HEAD>
321 <BODY BGCOLOR=FFFFEE>
322 <FORM>
323 <TABLE BORDER="O">
324 <TR>
325 cTD VALIGN=MIDDLE>
326 <IMG SRC="images/image-machine.qif" WIDTH=275 HEIGHT=56
HSPACE=25>
327 </TD>
328 <TD>
329 < ! - - Create a the default template / / - - >
330 <TABLE BORDER="O ALIGN="CENTER">
331 <TR>
332 <TD VALIGN="TOP">
333 <FONT FACE= Ar ial SIZE=2>
'I
368 Border
369 </TD>
370 <TD VALIGN="TOP">
371 <FONT FACE="Arial" SIZE=%>
372 <SCRIPT LANGUAGE="JavaScript1.2">
373 <!--
374 genSelect ("defbdr",10, 0, 0 ) ;
375 //-->
316 </SCRIPT>
377 </TD>
378 < TD VAL IGN=" TOP " >
379 <FONT FACE= Ar ial S IZE=2>
'I 'I
380 Height
381 < / TD>
3 82 <TD VALIGN="TOP">
383 <FONT FACE=" Ar ia1 " SIZE=2>
384 <SCRIPT LANGUAGE="JavaScriptl.2">
385 <!--
386 genselect ( "pxlheight", 250, 0, 5 0 ) ;
3 87 //-->
388 < /SCRIPT>
3 89 < / TD>
390 <TD VALIGN="TOP">
391 <FONT FACE=" Arial " S IZE=2>
392 <INPUT TYPE=BUTTON VALUE="Proceed"
393 onClick="captureDefaultProfile(this.form);">
394 </TD>
395 <TD VALIGN="TOP">
396 <FONT FACE="Arial" SIZE=2>
397 <INPUT TYPE=RESET VALUE=" Reset " >
398 </TD>
399 </TR>
400 </TABLE>
401 </TD>
402 </TR>
403 </TABLE>
404 </CENTER>
405 < /FORM>
406 </BODY>
407 </HTML>
1 . Carga de paginas.
2. El usuario introduce 10s pares de las imagenes y las opciones predetermi-
nadas y hace clic en eI boton "Proceed".
174 ImageMachhe
seleccionar de una lista desplegable. Per0 iquitn quiere crear una lista desplega-
ble con 250 o 300 valores diferentes? JavaScript nos puede ayudar con una
llamada a la funcion genselect ( ) para cada lista de seleccion. Veamos el con-
tenido de las lineas 12-1 9:
captureDefaultProfile()
La primera funcion a la que se llama cuando el usuario hace clic sobre el boton
"Proceed, es CaptureDefaultProf i l e ( 1 . En las lineas 21-39 podemos ver su
contenido:
function captureDefaultProfile(form0bj) {
setArrays ( ) ;
imgDefaults = form0bj;
var imgQty = (imgDefaults.imgnumber.selected1ndex + 1 ) ;
var imgHeight = (imgDefaults.pxlheight.selected1ndex);
var imgwidth = (imgDefaults.pxlwidth.selected1ndex);
var imgBorder = (imgDefaults.defbdr.selected1ndex);
for (var i = 0; i < imgQty; i++) (
imgPrim[il = I"';
imgLink[il = "'I;
puede haber generado c6digo que se encargue de ello), la funcion 10s reiniciara
para que su valor inicial sea cero.
function setArrays0 {
imgPrim = new Array(
imgRoll = new Array(
imgDown = new Array(
imgLink = new Array(
imgText = new Array(
imgWdh = new Array();
imgHgt = new Array( ) ;
imgBdr = new Array( ) ;
I
imgText [ i] = "";
imgWdh[i] = imgWidth;
imgHgt[i] = imgHeight;
imgBdr[i] = imgBorder;
1
178 ImageMachine
generateEntryForm0
Lo ultimo que hara la funcion sera llamar a generateEntryForm ( ) . Aqui es
donde realmente empiezan a ocurrir cosas. Esta funcion es la unica responsable
de la creacion de la plantilla para imagenes personalizadas segun las opciones
del usuario. Veamos el contenido de las lineas 53-1 18 el codigo.
Un total de 66 lineas de codigo para una sola funcion. La verdad es que podemos
considerar que este caso es la exception a la norma. Pero generateEntryForm ( )
unicamente desarrolla una accion: crear la plantilla personalizada. Si la dividi-
mos en tres partes nos encontraremos con que las cosas se simplifican bastante.
Las tres partes son: las cabeceras de la tabla (TH),10s campos del formulario y
10s botones. Esta funcion efectua una serie de llamadas adocument .w r i t e l n ( .
Este es el codigo encargado de escribir las cabeceras de las lineas 54-72:
with(parent.frames[l].document) {
open ( ) ;
writeln("<HTMLxBODY BGCOLOR=FFFFEE><FONT FACE=Arial SIZE=2>" +
"<BLOCKQUOTE>Choose or enter the paths of all images in the + I'
"message you want to display in the status bar during the " +
"<FONT FACE=Courier>MouseOver</FONT>event. Then choose + 'I
+ "code in action.</BLOCKQUOTE><FORMNAME='imgProfile' +
"onSubmit='return false;'><CENTER><TABLEBORDER=O ALIGN=CENTER +
"CELLSPACING=5 CELLPADDING=5><TH ALIGN=LEFT><FONT FACE=Arial>#" +
"<TH ALIGN=LEFT><FONT FACE=Arial>Primary Path" +
"<TH ALIGN=LEFT><FONT FACE=Arial>Rollover Path" +
(imgDefau1ts.mousedown.checked? "<TH ALIGN=LEFT>" +
"<FONT FACE=Arial>MouseDown Path" : " " ) +
"<TR><TD><BR></TD></TR>") ;
}
ImaaeMachine 179
(imgDefau1ts.mousedown.checked ?
Nos encontraremos con uno de estos ejemplos cuando el usuario active la ca-
silla de verificaci6n "MouseDown",puesto que de esta forma se podra incluir el
c6digo responsable de agregar una imagen mAs a la secuencia asociada con 10s
botones.
Ya nos hemos encargado de las cabeceras y de 10s campos de texto del formu-
lario. Lo unico que queda es crear 10s botones: "Generate","Preview"y "Clear".
with(parent.frames[ll.document) {
writeln("</TABLE><CENTER><INPUT TYPE=BUTTON +
"onClick='parent.frames[0].imgValid8(this.form,true);' " +
"VALUE='Generate'>iINPUTTYPE=BUTTON +
"onClick='parent.frames[O].imgValid8(this.form,false);' " +
180 IrnageMachine
close ( ) ;
1
imgTemplate['seci' + i] .value == II
"'I
Esta funcion se asegura de que el usuario ha rellenado todos 10s campos co-
rrespondientes a las rutas de las imagenes. En realidad, no es algo que se tenga
que hacer obligatoriamente, per0 nunca esta de mas comprobar si las ha inclui-
do. No olvidemos que el boton "Generate"entrega una copia del formulario, in-
cluyendo informacion de las imagenes.
Esta copia se le asigna a imgTempZate. Una vez mas, utilizando imgPrim, la apli-
caci6n repetira el proceso a travks de todos 10s campos de texto que contengan
la ruta de las imagenes. El campo que tiene la ubicacion de la imagen principal
ImaneMachine 181
genJavaScriptO
Si hay algun campo vacio, se le comunicara a1 usuario y se volvera a ejecutar
la funci6n. Si todos tienen una cadena de texto, ImageMachine llamara a la
funci6n genJavaScript0, le pasara imgTempZate y el booleano que se encuentre
dentro de mimeType. Como podemos suponer, la funci6n genJavaScript ( ) se
encargara de crear el codigo JavaScript de la pagina Web que aparecera en la
pantalla. La funcion es muy larga, sin embargo, funciona de la misma manera
que generateEntryForm(1. Veamos las lineas de codigo 138-306.
182 ImageMachine
if (mimeType) {
It = "&It;";
gt = " > ; an ;
br = <BR>'*;
'I
HTML = true;
nbsp = " ";
1
else {
It -
- "<" .
gt = > ;
'I
br = lb;
HTML = false;
nbsp = '' I8 .
1
Sigamos, HTML (cuyo valor es false)es una variable booleana que nos indica
cuando el usuario desea se proceda con la interpretacion del codigo. Lo veremos
a1 pasar a1 estudio de la generacion del c6digo. L a variable nbsp sera igual a una
cadena vacia.
Ahora, ImageMachine tiene la informacion de las cadenas de texto de la planti-
lla, independientemente de que el usuario quiera ver o ejecutar el codigo. L a ge-
neracion del codigo JavaScript no tendra lugar hasta que se alcance la linea 185
y se desarrollara hasta el final de la funcion.
Segun avancemos por el codigo, nos encontraremos con varias llamadas a
p a t h p r e p ( 1 . Esta funcion se encarga de volver a dar formato a la cadena don-
de se encuentra la ruta de la imagen. Esta accion unicamente se desarrollara
cuando la ruta sea local. iPor que tanto lio? Bueno, recordemos que Windows
utiliza la notacion basada en barras invertidas (\) para separar 10s directorios.
Los exploradores trabajan con otra notacion, basada en la barra inclinada (/),
184 ImageMachine
igual que 10s sistemas Unix. Por lo tanto, sera necesario convertir las barras
invertidas en barras inclinadas. En la actualidad, ciertos exploradores hacen la
conversion sobre la marcha.
El problema consiste en que JavaScript interpreta el caracter barra invertida
como parte de un caracter de separacion. Por lo tanto, JavaScript tomara la ca-
dena C:/Mi-directorio/Mi.archivo como C:Mi-directorioMi.archivo. La funcion
p a t h p r e p ( ) se encarga de todo. En las lineas 310-317 tenemos su codigo:
function pathPrep(path) I
i f (path.indexOf( " : \ \ " ) ! = -1) I
path = path.replace(/\\/g, " / " ) ;
path = path.replace(/:\//, " I / " ) ;
return "file:/ / / " + path;
if(imgTemp1ate ! = null) {
setArrays ( ) ;
IrnaaeMachine 185
Si se modifican 10s elementos del array, 10s valores de la cadena que se les asig-
ne pasaran a travts de un proceso (rhpido y peligroso) de la mano de la funcion
purify ( ) en la linea 308.
De esta forma eliminamos todas las comillas simples y dobles de 10s valores.
N o hay nada ilegal en esto, pero JavaScript utiliza estas comillas para generar el
c6digo. A menos que esttn perfectamente aisladas con barras invertidas, las
comillas nos pueden provocar mas de un dolor de cabeza. La funcion purify ( )
se encarga de eliminarlas de todas las cadenas que se le pasan, generando una
nueva completamente limpia.
Generar el codigo
Ya ha llegado el momento que tanto esperhbamos: la generaci6n del codigo.
Tiene lugar en las lineas 185-305. Asigna todo el c6digo generado a varias va-
riables. Dichas variables seran las siguientes:
PrimJavascript. Contiene etiquetas HTML como HTML, HEAD y TITLE.
Tambitn contiene el JavaScript preliminar, el codigo JavaScript preliminar
y el asociado con la imagen de la secuencia correspondiente a 10s eventos
MouseOver y MouseOut .
secJavaScript. Contiene el c6digo asociado con el evento MouseDown de
JavaScript 1.2.
inzagelinks. Contiene una etiqueta SCRIPT de cierre.
swapcode. Contiene las funciones de JavaScript que se encargaran de las
secuencias de las imhgenes.
primcode. Contiene la etiqueta BODY y algunos comentarios HTML.
secHTML. Contiene las etiquetas HTML de cierre y 10s botones "From"que
se muestran una vez que se ha generado el c6digo.
agregate. Esta variable representa el resultado de sumar todas las variables
anteriores.
186 ImaneMachine
El buclefor de la linea 197 se repetira las veces que determine imgprim. lenght.
Con cada repeticion, se aiiaden las variables primJavascript, secJavaScript (si el
usuario selecciona la opcion MouseDown) e imageLinks a1 c6digo correspondien-
te con la siguiente repeticion del grupo de imagenes.
Las variables scriptCZose,swapcode, primHTML y secHTML no forman parte del
bucle for. Su contenido se puede determinar a travks de un operador ternario
junto con la variable HTML e imgDefauIts.mousedown.checked.
Cuando se complete el buclefor y se hayan configurado las variables, tendre-
mos que hacernos con el contenido de la pagina. Esto tiene lugar en las lineas
300-305:
agregate = primJavascript +
(imgDefau1ts.mousedown.checked ? scriptclose + SecJavaScript : "") +
swapcode + primHTML + imageLinks + secHTML;
parent.frames[ll.location.href =
" javascript : parent. frames [ 0 I .agregate" ;
<SCRIPT LANGUAGE="JavaScript1.2">
< I --
genSelect("vspace", 2 5 , 0, 0);
//-->
</SCRIPT>
</TD>
De esta forma hacemos algo de sitio para guardar 10s nuevos valores predeter-
minados. Esto nos lleva a1 siguiente paso.
ImageMachine 189
function captureDefaultProfile(form0bj) {
setArrays ( ) ;
imgDefaults = formObj;
var imgQty = (imgDefaults.imgnumber.se1ectedIndex + 1);
var imgHeight = (imgDefaults.pxlheight.selected1ndex);
var imgWidth = (imgDefaults.pxlwidth.selected1ndex);
var imgBorder = (imgDefaults.defbdr.selected1ndex);
var imgHspace = (imgDefaults.hspace.selected1ndex);
var imgVspace = (imgDefaults.vspace.selected1ndex);
for (var i = 0; i < imgQty; i++) {
imgPrim[i] = "'I;
imgRoll[i] = "';
imgDown[i] = " " ;
imgLink[i] = " " ;
imgText[i] = ' I " ;
imgWdh[i] = imgWidth;
imgHgt[i] = imgHeight;
imgBdr[i] = imgBorder;
imgHSpace[i] = imgHspace; / / Para HSPACE
imgVSpace[i] = imgvspace; / / Para VSPACE
1
generateEntryForm0;
1
"<TR><TDVALIGN=BOTTOM COLSPAN=" +
(!imgDefaults.mousedown.checked ? "3" : " 4 " )+ " 2 " +
"<BR><HRNOSHADE><BR>c/TD></TR>") ;
Este codigo aiiade dos campos adicionales para cada grupo de imagenes y mos-
trara el valor predeterminado de cada uno. El usuario podra cambiarlo cuando
quiera.
Las dos ultimas lineas del bloque muestran la aplicacion asignando 10s valores
del formulario de la plantilla de imagen a 10s elementos irngHspace e irngvspace.
Ya casi lo tenemos. Solo nos queda asegurarnos de que se incluyen 10s nuevos
atributos en el proceso de generacion, impresion o interpretacion del codigo.
Hemos aiiadido dos atributos para las imagenes. Podemos aiiadir tambiCn una
etiqueta ALT para el contenido de dicha imagen. Este tipo de modificaciones rea-
lizadas a la etiqueta I MG no tiene ningun limite. Con la etiqueta <A> tambitn se
puede hacer muchas cosas. Podemos personalizarla para las imagenes compues-
tas a partir de mapas de bits, etc.
Capitdo 6
Implementaci6n de archivos de c6digo fuente en JavaScript
Si ha seguido 10s capitulos desde el principio (en orden, claro) habra tratado de
comprender como trabajan juntas las variables y las funciones para que las
aplicaciones vistas hiciesen algo. Creo que merece la pena tomarse un descanso
y ver algunas cosas en este capitulo que nos faciliten la vida a la hora de crear
aplicaciones.
En este capitulo no encontrara ninguna aplicacion, sin0 unas cuantas funcio-
nes que suelen aparecer en el cddigo de JavaScript. Aunque no todas serviran la
mayoria de las veces, hay unas cuantas funciones que se podran personalizar y
utilizar con nuestras aplicaciones.
La finalidad de incluir estos archivos no es la de ponerlos en manos de 10s pro-
gramadores para que se busquen la vida. Todo lo contrario. En estas paginas in-
tentark animar a 10s lectores a crear bibliotecas de codigo para que las vuelvan
a utilizar siempre que haga falta. Asi, no tendran que reinventar la rueda cada
vez que escriban una nueva aplicacion. La lista que veremos en breve se compo-
ne de archivos .js, ordenados alfabkticamente, junto con la finalidad de cada uno
de ellos.
arrays.js. Contiene una serie de funciones especializadas en la manipula-
cion de arrays. Algunas de estas funciones le permiten desarrollar acciones
equivalentes a las de JavaScript 1.2 en exploradores que no son compatibles
con esta version del lenguaje.
cookies.js. Esta biblioteca, una de las primeras que creo Bill Dortch, facilita
bastante la vida del programador a1 crear cookies.
dhtrnZ.js. Aqui veremos algunas de las funciones de 10s capitulos 3 y 4. Es
un paquete muy interesante para crear capas DHTML.
194 Implementaci6n de archivos de c6digo fuente en JavaScript
arrays.js
Us0 practico
Manipulacion de arrays.
Version necesaria
JavaScript 1.2.
Funciones
avg ( ) , high ( ) , low ( ) , jsGrep ( ) , truncate ( ) , shrink ( ) , integrate ( ) ,
reorganize ( ) .
Estas funciones toman nuestros arrays, 10s manipulan y devuelven algun tip0
de informacion de utilidad, incluyendo otros arrays. En la figura 6.1 tenemos el
contenido de arrays.htmZ. No hay nada especial, unicamente que se puede ver la
demostracion de cada funcion.
Imdernentacion de archivos de c6digo fuente en IavaScriDt 195
O n g d A m y . 1,2,3,0 1 0 9 8 ~ . 1 . 3 . 4 5 6 . 1 3 2 4 . 5 , ~ . 7 6 C I . 3 C Z Z Y p m M B
Aver= 82 43633684210526
Lowcrt -076
&hest 1324 55
T m a t e by 1 1.2.3.0 1098.5.2.3456.1324 5
:
O 76.45.3.47 234.0 0006.657.1.3.2.4
Shmk by 1 2.3.0 1098.5.2.3 456.1324 55.-076.45.3.47 2M.O 0006.65 7.1.3.2.4
Rcor-(by 4) 1.5.-076.0 0006.2,2.2.45.657.4.3.3 456.3.1 .O 1098.1324 55.47 234.3
:r onc.Onc mom.2.3456.1324 55,-
r w m M NSM
< /HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript 1.2 " >
<!--
196 lmplementacion de archivos de codigo fuente en JavaScript
Como se puede ver, las dos etiquetas SCRIPT han de trabajar con la version 1.2
de JavaScript. L a unica razon para ello es la existencia de la funcidn j s G r e p ( )
que utiliza las propiedades de localizacion y sustitucion de JavaScript 1.2. Vere-
mos mas sobre j s G r e p ( ) en un instante. Podemos hacer que 10s exploradores
compatibles con JavaScript 1.1 tambiCn trabajen con este c6digo. Para ello eli-
minaremos (0volveremos a escribir) j s G r e p ( ) . Ahora que ya hemos visto como
se llama a las funciones, vamos a centrarnos en el contenido de las propias fun-
ciones. En el ejemplo 6 . 2 tenemos el contenido del archivo arrayxjs.
1 var sum = 0;
2 for (var i = 0; i < arr0bj.length; i++) {
3 sum += arrObj[i];
4 I
5 return (sum / i);
6 >
7
8 function high(arr0bj) {
9 var highest = arrObj[Ol;
10 for (var i = 1; i < arr0bj.length; i++) {
11 highest = (arrObj[il > highest ? arrObj[i] : highest);
12 1
13 return (highest);
14 I
lmplementacion de archivos de codigo fuente en JavaScript 197
15
16 function low(arr0bj) {
17 var lowest = arrObj[O];
18 for (var i = 1; i < arrObj.length; i + + ) (
19 lowest = (arrObj[il < lowest ? arrObj[il : lowest);
20 }
21 return (lowest);
22 I
23
24 function jsGrep(arrObj, regexp, subStr) (
25 for (var i = 0; i < arrObj.length; i++) (
26 arrObj [il = arrObj [il.replace(regexp,subStr);
21 }
28 return arr0bj;
29 I
30
31 function truncate(arr0bj) (
32 arrObj.length = arrObj.length - 1;
33 return arrObj;
34 I
35
36
37 function shrink(arr0bj) {
38 var tempArray = new Array();
39 for(var p = 1; p < arr0bj.length; p++) (
40 tempArray[p - 11 = arrObj [PI ;
41 1
42 return tempArray;
43 1
44
45
46 function integrate(arrObj, elemArray, startIndex) (
47 startIndex = (parseInt(Math.abs(start1ndex))< arr0bj.length ?
48 parseInt(Math.abs(start1ndex)) : arrObj.length);
49 var tempArray = new Array( ) ;
50 for( var p = 0; p < startIndex; p++) (
51 tempArray[pl = arrObj [PI ;
52 1
53 for( var q = startIndex; q < startIndex + elemArray.length;
q++) (
54 tempArray[ql = elemArray[q - startIndex1;
55 }
56 for( var r = startIndex + elemArray.length; r < (arrObj.length
57 + elemArray.length); r + + ) {
58 tempArray[r] = arrObj[r - elemArray.length1;
59 1
60 return tempArray;
61
62
63 function reorganize(formObj, stepup) (
64 stepUp = (Math.abs(parseInt(stepUp))> 0 ?
198 lmplementacidn de archivos de codigo fuente en JavaScript
65 Math.abs(parseInt(stepUp)) : 1);
66 var nextRound = 1;
67 var idx = 0;
68 var tempArray = new Array() ;
69 for (var i = 0; i < formObj.length; i++) {
70 tempArray[il = formObj[idx];
71 if (idx + stepUp >= formObj.length) (
72 idx = nextRound;
13 nextRound++;
74 )
75 else {
76 idx += stepup;
77 )
18
19 return tempArray;
80 1
Las funciones avg ( ) , high ( ) y l o w ( ) no parecen nada del otro mundo. avg ( )
suma todos 10s valores y divide el resultado entre arrObj .length. Devuelve el
cociente de la operacion. Las otras dos funciones se repiten a traves del array
que se les ha entregado, comparando cada elemento con el que esta delante suyo,
hasta que a1 final se obtiene el valor mas alto o mas bajo del grupo.
La funcion j sGrep ( ) se repite con todos 10s elementos del array y ejecuta una
cadena de localizacion o busqueda. Cualquiera que este familiarizado con Perl
posiblemente habra utilizado la subrutina grep ( ) . La version de Perl es bastan-
te mas potente que ksta, per0 siempre podremos decir que se parecen.
Las funciones truncate ( ) y shrink ( son equivalencias en JavaScript 1.1 de
las funciones pop ( ) y shift ( ) de JavaScript 1.2. En realidad,pop ( ) y shift ( )
reciben su nombre de las rutinas de Perl a las que tanto se asemejan.
La funcion integrate ( ) tambien es una equivalencia para JavaScript 1.1 del
metodo slice ( ) de JavaScript 1.2.
El nombre de slice ( ) tambien procede de Perl. Esta funci6n es muy sencilla.
Aunque contiene tres bucles for, el ndmero total de iteraciones siempre sera
arrObj.length + elemArray.length.
La funcion reorganize ( ) reordena 10s elementos del array a partir del mdltiplo
que seleccionamos. En otras palabras, si Yeorganizamosl' un array de 10 ele-
mentos (compuestos por: 0, 1, 2, 3, 4, 5 , 6, 7, 8 y 9) por 3, el nuevo orden sera
0,2,.5,8,1,4,7,3,6,9.
cookies.js
Us0 prictico
Contadores individuales, formularios y preferencias de usuarios.
Implernentacion de archivos de codigo fuente en JavaScript 199
Version necesaria
JavaScript 1.1.
Funciones
getcookieVal (), Getcookie ( ) , Deletecookie ( ) , Setcookie ( 1 .
iQueremos conocer el estado de administracion del lado del cliente? iQue hay
de esos saludos que algunos sitios Web ofrecen a 10s usuarios que vuelven a
visitar sus paginas Web? LNecesita configurar una interfaz que cambie de idio-
ma o cualquier otra preferencia del usuario? Este c6digo esta especializado en la
creacion y obtencion de la informacion almacenada en las cookies. En las figu-
ras 6.2, 6.3 y 6.4 podemos ver cookies.htm1 en accion. En la primera de ellas,
podemos ver qu6 ocurre la primera vez que se carga la pagina. Se le pide a1
usuario que facilite su nombre. En la figura 6.3 se muestra un saludo a1 usuario
que accede por primera vez a estas paginas Web. En la figura 6.4 se puede ver el
saludo que recibe un usuario que accede de nuevo a dicha pagina.
Figura 6.3. Mensaje de bienvenida que se muestra la primera vez que accedemos
a la pagina Web
Ilio”um- ~ ~ -.-.
..._________
f -!---r;;iiiii-------,
3
Figura 6.4. Mensaje de bienvenida que se muestra las sucesivas vece5 que arcedemos
a la phgina Wet)
41 1
dhtml.js
Us0 prictico
Crear, ocultar y mostrar capas DHTML.
Version necesaria
JavaScript 1.2.
Funciones
genLayer ( 1, hideslide ( ) , showslide ( ) , refslide( ) .
Si hemos lefdo el contenido de esta obra en orden, ya conoceremos este codigo
porque nos lo hemos encontrado en dos de las aplicaciones anteriores (el ejem-
plo de las diapositivas y la interfaz del motor de busqueda). En las figuras 6.5 y
6.6 podemos ver el codigo que se ha utilizado para crear la capa y como nos per-
mite mostrarla u ocultarla.
En el ejemplo 6.4 tenemos el contenido correspondiente a1 archivo dhtrnl.js. No
he cambiado nada. Si quiere mas detalles sobre este codigo, consulte 10s capitu-
10s anteriores.
Imdernentacion de archivos de codiao fuente en IavaScriDt 203
I . .
[%Ids1IShowl
Y .
--_I_
rr-rwm __=6 I
Figura 6.6. ... dhora 110 lo vcs
11 }
12 else {
13 document.writeln('<DIV ID="' + sName +
14 "' STYLE="position:absolute; overf1ow:none;left:' + sLeft +
15 'px; top:' + sTop + 'px; width:' + sWdh + 'px; height:' +
sHgt +
16 'px; visibility:' + svis + ' z-Index=' + (++zIdx) + " ' > ' +
204 lmplementacion de archivos de codigo fuente en JavaScript
17
18
19
20
21 function hideSlide(name) I
22 refSlide(name).visibility = hideName;
23 1
24
25 function showSlide(name) t
26 refSlide(name).visibility = showName;
27 >
28
29 function refSlide(name) t
30 i f (NN) ( return document.layers[namel; >
31 else { return eval('document.al1.' + name + '.style');1
32 >
events.js
Us0 practico
Seguimiento del movimiento del raton y asignaci6n del controlador de eventos
compatible con diferentes exploradores.
Version necesaria
JavaScript 1.2.
Funciones
enableEffects0, showXY0, keepKeys0, showKeys0.
Si aun no ha probado a controlar eventos de forma que Sean compatibles con
varios exploradores Web, aqui tiene su primer ejemplo. Trabajamos con tres
controladores: ondick, onmousemove y onkeypress. La primera vez que se hace
clic en algun punto del documento, JavaScript captura las coordenadas x e y del
cursor tomando como referencia la ventana del explorador. A continuacih, la
barra de estado mostrara las coordenadas del cursor, segun se mueva por la pan-
talla. Si volvemos a hacer clic, desactivaremos el seguimiento de coordenadas y
calcularemos la distancia (en pixeles) que hay entre el primer punto en el que se
hizo clic y la posicibn actual del cursor. En las figuras 6 . 7 y 6.8 lo podemos ver
en accion.
Independientemente de la accion del raton, podemos escribir cualquier secuen-
cia de teclas a traves del teclado. En la barra de estado apareceran las teclas que
se vayan pulsando. Cuando terminemos, podremos hacer clic en el boton "Show
Keys" que se encuentra en la pantalla y la funci6n nos presentara un cuadro de
dialog0 donde mostrara la secuencia de teclas. En la figura 6.9 podemos verlo.
Para volver a empezar otra vez desde el principio, haremos clic en el b o t h "OK".
Implementation de archivos de codigo fuente en JavaScript 205
Chck your mouse button. then move tt around, chck agm to stop traclrmg
Now type some keys any keys ?hen press shout Keys
Now type some keys any keys Thm press Show Ksys
De momento bastar6 simplemente con que nos familiaricemos con las compli-
caciones que pueden tener las hojas de estilos que son compatibles con varios
exploradores.
Tenemos que saber que las etiquetas LAYER de un explorador, equivalen a las
etiquetas D I V de otro. Y en lo que se refiere a 10s tipos de eventos, las cosas tam-
poco resultan demasiado intuitivas que se diga. Si comprobamos el cddigo co-
rrespondiente a events.htmZ, nos encontraremos con las siguientes dos lineas de
JavaScript :
document.onclick = enableEffects;
document.onkeypress = keepKeys;
206 Implementaci6n de archivos de cddigo fuente en JavaScript
document.onclick = enableEffects0;
document.onkeypress = keepKeys0;
9 yl = ev.screenY;
10 document.captureEvents(Event.MOUSEM0VE);
11 I
12 else {
13 xl = event.screenX;
14 yl = event.screenY;
15 1
16 document.onmousemove = showXY;
11 }
18 else {
19 if (document.layers){
20 x2 = ev.screenX;
21 y2 = ev.screenY;
22 document.releaseEvents(Event.MOUSEM0VE);
23 f
24 else I
25 x2 = event.screenX;
26 y2 = event.screenY;
21 document.onmousemove = null;
28 }
29 window.status = 'Start: ( ' + Xl + ' , ' + yl +
30 End:
8 )+ x2 + + y2 + ' ) Distance: ' +
( 8 I , '
40 I
41 else { alert('Y0u have to type some keys first.'); }
42 I
41
44 function showxY(ev1 (
45 if (document.al1) ( ev = event; }
46 window.status = 'x: + ev.screenX + ' Y: ' + ev.screenY;
I
41 1
48
49 function keepKeys(ev) {
50 if (document.1ayer.s) I
51 keys += String.fromCharCode(ev.which);
52 window.status : 'Key pressed: ' +
String.fromCharCode(ev.which);
53 I
54 else {
55 keys += String.fromCharCode(event.keyCode);
56 window.status = 'Key pressed: ' +
String.fromCharCode(event.keyCode);
208 lmplementacion de archivos de codigo fuente en JavaScript
57 1
58 1
if (change) { ....
else { . ...
change = !change;
if(docurnent.layers) (
xl = ev.screenX;
yl = ev.screenY;
document.captureEvents(Event.MOUSEM0VE);
1
else {
xl = event.screenX;
yl = event.screenY;
1
document.onmousemove = showXY;
lmplementacidn de archivos de codigo fuente en JavaScript 209
function showXY ( ) in both browsers. Let ' s have a quick look at showXY ( 1 :
function showXY(ev1 {
if (document.al1) { ev = event; 1
window.status = 'X: + ev.screenX + ' Y: ' + ev.screenY;
1
Se llama a showKeys ( cada vez que se mueve el raton para que se muestren
las coordenadas del cursor en la pantalla. La referencia a 10s valores x e y es
identico a la vista anteriormente. Las llamadas a showKeys ( ) se repetiran cons-
tantemente hasta que el usuario vuelva a hacer clic, con lo que se invocara a la
funcion enableEf f ects ( ) . En cualquier caso, el valor de la variale change sera
false. Podemos ver la llamada entre las lineas 19-31:
if (document.layers) {
x2 = ev.screenX;
y2 = ev.screenY;
document.releaseEvents(Event.MOUSEM0VE);
1
else {
x2 = event.screenX;
y2 = event.screenY;
document.onmousemove = null;
1
window.status = 'Start: ( ' + xl + 0 '+ yl +
' ) End: ( ' + x2 + ' , ' + y2 + ' ) Distance: ' +
(Math.round(Math.sqrt(Math.pow((x2 - xl), 2)+ Math.pow((y2 - yl), 2 ) ) )
+ ' pixels';
Las variables xl e y l contienen 10s valores del punto inicial. Ahora, las varia-
bles x2 e y2 contienen 10s valores del punto final. Ya no hay ninguna necesidad
de continuar con el proceso del controlador del evento onmousemove. Asi que,
con Navigator, se llamara a1 metodo releaseEvents ( ) con objeto de que in-
tercepte el evento mousemove. Obtendremos el mismo resultado con MSIE con
document.onmousemove.
Todo lo que queda es mostrar la distancia que hay entre el punto inicial y el fi-
nal. LRecuerda la formula de la distancia? Se utilizaba en el colegio. Es la misma
que se muestra en las lineas 29-3 1 .
Se hace cargo de 10s controladores de eventos onclick y onmouseover, dejando
solo aonkeypress. No olvidemos que se configuraba document.onkeypress para
que llamase a la funcion keepKeys ( ) en la carga de evenkhtml. En las lineas
49-58 se encuentra dicha funcion:
210 Imdementacion de archivos de c6dino fuente en IavaScriDt
function keepKeys(ev) {
if (document.layers) {
keys += String.fromCharCode(ev.which);
window.status = 'Key pressed: ' + String.fromCharCode(ev.which);
1
else {
keys += String.fromCharCode(event.keyCode);
window.status = 'Key pressed: +
String.fromCharCode(event.keyCode);
}
)
frames.js
Us0 practico
Carga de cuadros.
Version necesaria
JavaScript 1.1.
Funciones
keepIn ( ) , keepout ( 1 .
Irnplernentacion de archivos de codigo fuente en JavaScript 21 1
Este archivo de codigo fuente unicamente contiene dos funciones. Una guarda
10s documentos en un marco de trabajo determinado. La otra 10s guarda fuera
de el. frarnes.js necesita varias paginas HTML. Por ejemplo, trate de cargarlo en
su explorador Web. El archivo tiene dos cuadros. Uno de ellos utilizafrarnes.htrnZ
como fuente. Dicho archivo utiliza frarnes.js para asegurarse de que se carga
frarnes.htrnZ en la parte superior de la ventana. Esta es la raz6n por la cual la car-
ga defrarneset.htrn2ofrece el resultado de las figuras 6.10 y 6.1 1 (el explorador
carga frarneshtrnl).
Por el contrario, para todos aquellos que quieran asegurarse de que no se car-
gan 10s archivos a menos que se encuentran en un marco de trabajo predetermi-
nado, podran utilizar frarnes.js. Veamos el contenido de la figura 6.10. Aparece
un aviso el cual nos indica que se ha tratado de cargar un archivo dentro del
marco equivocado.
En la figura 6.1 1 vemos el resultado que obtenemos si cargamos el archivo en
el cuadro correcto.
El codigo que se utiliza para acomodar esta funcionalidad es muy corto. La fun-
cion keepout ( ) compara el URL del documento que se encuentra situado en la
parte superior de la ventana con el del cuadro actual. Si no coinciden las propie-
dades l o c a t i o n . href, keepout ( ) entonces protestara y nos mostrara un aviso,
212 Irnplernentacion de archivos de cddigo fuente en JavaScript
1 function keepout0 (
2 if (top.location.href ! = self.1ocation.href) {
3 alert('This document bows to no frameset.');
4 top.location.href = self.location.href;
5 I
6 >
I
8 function keepIn(parentHREF) (
9 if (top.location.href == se1f.location.href) (
10 alert("Wheez1. . . [Gasp]. . . Must. . . load. . . ' +
11 'original. . . frameset.');
12 top.location.href = parentHREF;
13 I
14 I
lmplementacion de archivos de codigo fuente en JavaScript 213
images.js
Us0 practico
Secuencias de imagenes.
Version necesaria
JavaScript 1.1.
Funciones
imagePreLoad( ) , imageswap( ) , display ( ) .
Al igual que ocurria con las funciones de dhtmZ.js, ya hemos visto en capitulos
anteriores el codigo de images.js. De hecho, en 10s tres capitulos anteriores se han
visto distintas versiones de las lineas que aparecen en el ejemplo 6.7. Podemos
cargar las imagenes de antemano y utilizarlas como secuencias dependientes
del raton.
15 eval (arrayHandles[j] + '' [ " + idx + " I .src = ' " + imgPath +
imgName +
16 arrayHandles [jI + " .gif'" ) ;
17 1
18 1
19
20 function imageSwap(imagePrefix, imageIndex, arrayIdx) I
21 document[imagePrefix].src = eval(arrayHandles[arrayIdxl + "[" +
22 imageIndex + " 1 .src");
23 1
24 function display(stuff) { window.status = stuff; )
navbar.js
Us0 practico
Navegacion dinamica por la phgina.
Version necesaria
JavaScript 1 . 1 .
Funciones
navbar ( 1 .
Este archivo de codigo fuente solo contiene una funcion. Supongamos que te-
nemos varias paginas de contenidos en un sitio Web, cada una de ellas con una
barra de navegacion con vinculos a otras paginas. LNo estaria bien que JavaScript
creara una barra de navegacion inteligente que incluyese vinculos a1 resto de pa-
ginas del sitio Web menos a la que aparece en pantalla? La figura 6.12 muestra
una pagina Web con una barra de contenidos con vinculos a otras paginas.
ningun enlace con la pagina Cool People porque es la que aparece en pantalla.
Este sistema se puede utilizar con todas las paginas que deseemos. Lo unico que
hay que hacer es modificar el contenido de navbar.js. Nos ahorraremos mucho
tiempo.
numbers.js
Us0 practico
Corregir 10s errores de redondeo y el formato de numeros para 10s programas
de compra dentro del comercio electronico (tambikn conocidos como carru de la
cumpra).
Version necesaria
JavaScript 1.1.
Funciones
twoPlaces0, round(),totals().
JavaScript trabaja con 10s numeros con coma flotante de forma distinta a la
esperada. Como el resultado se obtiene a partir de numerosos calculos, es posi-
ble que difiera del esperado (por ejemplo, a1 multiplicar 0,119 * 100 se obtiene
11,899999). Las funciones de numbers.js se han diseiiado para ayudar en am-
bas situaciones. Las tres se basan en las funciones que en su dia escribio Martin
Webb. Podemos verlas en accion en la figura 6.14.
Los numeros que aparecen bajo "Two Decimal Places" nos muestran el formato
que usa la funcion twoplaces ( ) para trabajar con Euros y ckntimos. Las otras
dos cabeceras muestran la diferencia que existe entre una expresion a1 utilizar
las funciones r o u n d ( ) y totals ( ) y a1 no utilizarlas. A1 final vemos la opcion
que se suele utilizar. En el ejemplo 6.9 se puede ver el contenido correspondiente
a numbers.js.
tmplementacion de archivos de codigo fuente en JavaScript 21 7
I
gjiTU0 - r -GJ*-=-- --*/
A
La funcion twoplaces ( ) devuelve una cadena con el valor del numero, a1 cual
le afiade . 0 6 . 00, o nada si el formato utilizado es el correcto. Esta expresion
condicional se podria traducir a1 castellano de la siguiente manera:
En el caso de que el numero sea igual a1 entero inmediatamente inferior
(Math.f l o o r (amount) ), entonces devuelve una cadena a la que afiade a
continuacion . 0 0.
218 lmplementacion de archivos de codigo fuente en JavaScript
Para 10s errores de redondeo, la funci6n round ( ) devuelve el numero per0 con
x decimales. Por defecto, el valor inicial de x es 2. Por lo tanto, el redondeo ini-
cia1 sera . 00. L a funcion total ( ) se limita a llamar otra vez a twoplaces ( )
per0 se ha disefiado para que acepte una expresion de varios valores, por ejem-
plo, 51.02 - 3 . 8 como formato final.
objects.js
Us0 prictico
Creacion de objetos gentricos, inspeccion de objetos.
Version necesaria
JavaScript 1.1.
Funciones
makeObj ( ) , parseObj ( ) , obj Prof ile ( ) .
Ahora le toca el turno a 10s objetos de JavaScript. Con ellos se puede hacer tan-
tas cosas que apenas tenemos tiempo para probarlas todas. objects.js nos ofrece
dos utilidades. Una es u n constructor de objetos genericos y la otra un inspector
de objetos basicos. En la figura 6.15 podemos ver de qu6 estamos hablando.
Las funciones del inspector de objetos, parseObj ( ) y objProf ile ( ) revelan
las propiedades de dos objetos: uno representado por la variable someobject y el
otro es la ubicacion de la ventana de dicho objeto. Vamos a echar u n vistazo a1
contenido del ejemplo 6.10, que es el codigo de objects.htrnZ.
1 <HTML>
2 <HEAD>
3 <TITLE>objects.js Example</TITLE>
4 <STYLE type="text/css 'I>
5 <!--
6 td { font-family: courier new; font-size: 14)
I -->
8 < /STYLE>
9 <SCRIPT LANGUAGE="JavaScriptl .lo'SRC= "objects . js"></SCRIPT>
10 </HEAD>
lmplementacion de archivos de codigo fuente en JavaScript 219
11 <BODY>
12 <SCRIPT LANGUAGE="JavaScriptl.I " >
13 <!--
14
15 function plain01dObjectO {
16 this.name = 'some name';
17 this.numba = 1000;
18 this.objInherit = new makeObj('propertyOne', 'thisProperty'
19 ,propertyTwo', OthatProperty', 'propertyThree',
'theOtherProperty');
20 return this;
21 1
22
23 var someobject = new plain01dObjectO;
24
25 document.write(objProfile('some0bject'. 'self.location'));
26 //-->
27 </SCRIPT>
28
29
30
Object Profile
1 function makeObj ( ) {
2 if (arguments.length 8 2 ! = 0) {
3 arguments[arguments.length] = " " ;
4 I
5 for ( var i = 0; i < arguments.length; i += 2 ) {
6 this[arguments[ill = argumentsfi + 11 ;
7 1
8 return this;
9 I
10
11 function parseObj(obj) {
12 var objStr = " ;
13 for (prop in obj) {
14 objstr += '<TR><TD>Property:</TD><TD><B>' + prop +
15 '</B></TD><TD>Type:</TD><TD><B>' + typeof(obj[prop]) +
16 '</B></TD><TD>Value:</TD><TD><B>' + obj[prop] +
17 '</B></TD></TR>';
18 if (typeof( o b j [prop]) == "object") (
19 objStr += parseObj (obj[prop] ;
20 1
21 1
22 return objstr;
23 }
24
25 function objProfile0 (
26 var objTable = '<TABLE BORDER=2 CELLSPACING=O><TR><TD><Hl>'+
27 'Object Profile</Hl></TD></TR>';
28 for (var i = 0; i < arguments.length; i++) {
29 objTable += '<TR><TD><BR><BR><H2><TT>'+ (i + 1 ) + ' ) ' t
30 arguments[i] + '</H2></TD></TR>';
31 objTable + = '<TR><TD><TT><TABLECELLPADDING=5>' +
32 parseObj(eval(arguments[il)) + '</TABLE></TD></TR>';
33 }
34 objTable += '</TABLE><BR><BR><BR>';
35 return objTable;
36 1
this.name = 'Madonna'
this.ocupation = 'cantante/letrista'
Por lo tanto, la variable objInherit ahora hace referencia a un objeto que tiene
las siguientes propiedades:
objInherit.property0ne = 'thisProperty';
objInherit.propertyTwo = 'thatProperty';
obj1nherit.propertyThree = 'theOtherProperty';
Obskrvese que 10s valores de todas las propiedades es una cadena. Con ella, po-
dremos pasar numeros, objetos, etc. La funcionmakeobj ( ) se utiliza para crear
varios objetos, cada uno con propiedades diferentes y sin tener que definir un
constructor para cada uno de ellos.
El otro objeto que revisaremos sera el encargado de determinar la ubicacion.
Komo se formaliza la inspecci6n? Las funciones ob jProf ile ( ) y parseOb j ( )
trabajan juntas en las propiedades del objeto para crear una tabla de resultados.
Cada fila de la tabla identifica el nombre, tip0 y valor de la propiedad del objeto.
Empecemos con objProf ile ( ) :
function objProfile0 (
var objTable = '<TABLE BORDER=2 CELLSPACING=O><TR><TD><Hl>'+
'Object Profile</Hl></TD></TR>';
for (var i = 0; i < arguments.length; i++)
objTable += '<TR><TD><BR><BR><H2><TT>' + (i + 1 ) + ' + I )
arguments[il + '</HZ></TD></TR>';
objTable += '<TR><TD><TT><TABLECELLPADDING=5>' +
parseObj (eval(arguments[il)) + '</TABLE></TD></TR>';
222 Implementaci6n de archivos de codigo fuente en JavaScript
}
objTable += '</TABLE><BR><BR><BR>';
return objTable;
1
obj Prof ile ( ) es la funcion a la que se llama y a la que se entregan 10s para-
metros, como se puede apreciar en la linea 25 de objectxhtml:
document.write(objProfile('some0bject'.'self.location'));
Los argumentos no son objetos. Son cadenas. Per0 en breve reflejaran 10s obje-
tos. Al pasar el equivalente de la cadena, JavaScript podra mostrar estos objetos
basandose en el nombre de la pagina. Una vez que se crean las tablas TR y TD, se
entregan las cadenas de argumentos a obj Prof ile ( ) , que aplicara repetida-
mente el mCtodo eval( ) (linea 32)y pasara el resultado aparseObj ( ) .A con-
tinuacion, se ejecuta el siguiente extract0 de codigo:
Las cadenas se reciben como objetos y de hecho, se las llamar6 obj. Con el bucle
for...if, parseobj ( ) actuar6 sobre todas las propiedades de ubj, creando una ca-
dena con la propiedad, tipo, valor y etiquetas adecuadas de cada una de ellas.
Para que parseObj ( ) acceda a1 tipo de objeto, utilizara el operador typeof ( ) .
Una vez que se ha aiiadido a la cadena la propiedad, tip0 y valor, parseOb j ( )
comprobara si el tipo de la propiedad hace que Csta sea un objeto. En ese caso, se
ejecutara y entregara dicha propiedad (que sera un objeto obj). Gracias a este sis-
tema, puede profundizar en una jerarquia de objetos hasta alcanzar 10s elemen-
tos de cualquier nivel.
Cuando a parseOb j ( ) no le quedan mas objetos que analizar, se copiara el con-
tenido de la cadena de propiedades, tipos, valores y etiquetas en la variable objStr,
que se le devolvera a la funcion obj Profile ( ) .Esta cadena, que se guarda en
la variable objTable, se escribe a1 final de la pagina (linea 25 de objectxhtml).
Implernentacion de archivos de codigo fuente en JavaScript 223
document.write(objProfile('someObject','self.location'));
document.write(objProfile('document')) ;
document.write(objProfile('window'));
strings.js
Us0 prictico
Manipulacion, ordenacion alfabktica y contador de us0 para cadenas.
Version necesaria
JavaScript 1.2.
Funciones
camelcaps ( ) , prepStr ( ) , wordcount ( ) , reorder ( ) .
Estas funciones nos permiten conocer todo lo que se puede hacer con las cade-
nas que se generan a partir de la informacion que introducen 10s usuarios. Si
abrimos el contenido de stringhtmo en el explorador, nos encontraremos con el
contenido de la figura 6.16.
Tenemos tres formularios con 10s que intentaremos demostrar el desarrollo de
estas tres funciones. La primera contiene u n Area de texto (TEXTAREA).Despuks
de que el usuario introduzca el texto que desee y pulse el b o t h Tount'l, la fun-
cion wordcount ( ) generara una nueva pagina con una tabla. En dicha tabla se
mostraran todas las palabras que ha introducido el usuario y el numero de ve-
ces que se ha repetido cada una de ellas. Podemos ver 10s resultados que se ob-
tienen en la figura 6.1 7.
224 Imdementacion de archivos de codino fuente en JavaScriDt
50 I
51
52 var order = true;
53
54 function reorder(str) I
55 str = prepStr(str) ;
226 Irnplementacion de archivos de codigo fuente en JavaScript
Enrcr ~ o m words
c m Bc TEXTARUL below Then choose S m to sort Bc fcyf
SYailQulel: altablieclcm
tempArray[il = tempArray[il.charAt(O).toLowerCase()+
tempArray[il.substring(l);
I
1
return tempArray.join(' ' ) ;
}
El valor de la variable local tempArray sera un array que contiene todas las
palabras del texto. En este caso, una "palabra" sera cualquier porcion de texto que
se encuentre entre dos espacios en blanco. La sustitucion de las palabras no sera
otra cosa que repetir la funcion con todos 10s objetos. Cuando se complete el
cambio, la funcion devolvera una cadena con estas palabras unidas por medio
de espacios en blanco. La funcion camelcaps ( ) se limita a devolver 10s espacios
en blanco que se han eliminado durante la ejecucion de s p l i t ( 1 .
Para el ultimo formulario, la funcion reorder ( ) ejecutara un metodo s o r t ( )
ya sea normal o invertido. Aqui lo tenemos:
function reorder(str) {
str = prepStr(str);
str = str.replace(/\d/g, ; " ' I )
order = !order;
if(!order) ( str = str.split(' ').sort().join(' ' ) ; }
else ( str = str.split(' ').sort().reverse().join('' ) ; )
return str.replace(/"\s+f, " " ) ;
1
Las lineas 58-59 de strings.js utilizan el valor del orden para determinar quC
sistema han de usar. DespuCs devolveran la cadena (menos 10s espacios en blan-
co iniciales que se puedan haber creado a1 utilizar j o i n ( 1 ).
Posibles ampliaciones
Lo unico limite que tenemos aqui es el que nos queramos poner. Obviamente,
podemos agregar nuevas funciones o mejorar las ya existentes. La verdad es
que dud0 que nadie quiera conservar las funciones exactamente igual a como se
muestran en estos ejemplos. Posiblemente, se estC trabajando en el diseiio de un
sitio Web y se quieran utilizar estos archivos en dicho proceso. Estupendo. Todo
lo que se ha de hacer es fijar las funciones que se necesiten en un nuevo archivo
.js, con lo que se tendra una caja de herramientas de inestimable valor. Lo que se
ha de tener en cuenta es que conviene trabajar con el sistema que mejor se adap-
te a cada uno. N o deje que 10s archivos .js dirijan su trabajo.
Capitulo 7
Preferencias del usuario basadas en cookies
Este capitulo contiene una aplicacion muy normalita, per0 que no conviene
saltarse. iHe dicho que el codigo que se recoge en estas paginas es el responsable
de una de las funciones mas solicitadas en la Web? Hablo de las preferencias del
usuario. Considere esto. iQue es lo que tiene que tener todos 10s usuarios en la
cabeza cuando naveguen por la Web?
"Yo.
Pues si, 10s usuarios son bastante egoistas y siempre estan pensando en sus pro-
pios intereses. No importa lo que hagan. Siempre buscan cosas que les recuer-
den a si mismos. Esta es la raz6n por la que 10s seguidores de DHTML visitan
Dynamic HTML Zone (http://www.dhtmZzone.com/),10s consumidores del co-
mercio electronic0 acuden a Shopping.com (http://www.shopping.corn/ibuy/) y
10s amantes de la astronomia (como yo, ive? ya estoy hacikndolo de nuevo) vi-
sitan las paginas Web de Sky & Telescope (http://www.skypub.rom/).Los comer-
ciantes, anunciantes y comerciales llevan ya muchos aiios trabajando en W e .
Utilizando una aplicacion ficticia, en este capitulo comprobara lo sencillo que
resulta recordar el nombre de un usuario. Por medio de las cookies de JavaScript,
10s visitantes podran personalizar sin probelemas la visita que realicen a nues-
tra pagina Web.
Supongamos que estamos trabajando en el desarrollo de un sitio Web para
usuarios de Internet que tienen algo de dinero para invertir. Obtendran una sus-
cripcion gratuita a esta Bolsa ficticia, llamada Take-A-Dive Brokerage $ervices.
Nuestras paginas Web no les permitira mover dinero. Per0 el usuario podra per-
sonalizarlas para que le muestre 10s vinculos que mas le gusten, dirigidos a otras
paginas Web dedicadas a las finanzas o bien a noticias. En la figura 7 . 1 vemos el
232 Preferencias del usuario basadas en cookies
contenido que mostrara la aplicacion la primera vez que se accede a ella. Desde
aqui, el usuario podra personalizar su contenido.
lnvestor Profile
Investment Links
. . - ._
r Barrons Online
P CNN lnteracbve
NOW r FOXNM
P MSNBC
G The Wall Street Journal ~
'I
r Banon s Online
B CNN lnteractlve
P MSNBC
Figura 7.3. DespuCs de hacer clic en "Save",la aplicaci6n darh la opcion de ver
la pagina personaliza
Analisis de la sintaxis
Esta aplicacion consta de dos paginas HTML (prefkhtml y dive.htrnZ) y de un
archivo de codigo fuente en JavaScript, cookiexjs. La siguiente lista describe cada
uno de estos elementos:
cookies.js. Este archivo contiene las funciones que se han usado para escribir
las preferencias del usuario y para extraer la informacion de la cookie.
cookies.js esta dentro de 10s dos archivos HTML .Las funcionesGetCookie ( )
y S e t c o o k i e ( ) , que veremos en estos dos archivos, proceden de aqui.
Los archivos prefs.htrnl y dive.htrnl son nuevos, per0 cookies.js ya lo vimos en
el capitulo 6 . Si tiene alguna duda sobre el, revise dicho capitulo.
prefs.html
Aunque la secuencia de capturas de pantalla nos muestra la sucesion de accio-
nes (por ejemplo, el usuario inicia el proceso sin haber configurado ninguna
preferencia), en este ejemplo, vamos a asumir que eI usuario ya habia seleccio-
nado previamente alguna preferencia y quiere modificarla. Sera mas sencillo. El
ejemplo 7.1 muestra el contenido del archivo prefs.htrnl.
Ejemplo 7.1. prefs.htm1
1 <HTML>
2 <HEAD>
236 Preferencias del usuario basadas en cookies
3 <TITLE>Take-A-DiveUser Preferences</TITLE>
4 <STYLE type="text/css">
5 BODY, TD ( font-family: Arial; )
6 </STYLE>
I <SCRIPT LANGAUGE="JavaScriptl.2" SRC="cookies.js"></SCRIPT>
8 <SCRIPT LANGUAGE="JavaScriptl.2">
9
10 var imagepath = 'images/';
11 var newsNames = new Array(
12 new Array('The Wall Street Journal','http://www.wsj.com/'),
13 new Array('Barron\'s Online','http://www.barrons.com/'),
14 new Array('CNN Interactive','http://www.cnn.com/'),
15 new Array('MSNBC','http://www.msnbc.com/'),
16 new Array('Fox News','http://www.foxnews.com/')
17 ):
18
19 var indemames = new Array(
20 new Array('The New York Stock Exchange','http://www.nyse.com
'),
21 new Array('NASDAQ','http://www.nasdaq.com/'),
22 new Array('Dow Jones Indexes','http://www.dowjones.com/')
23 );
24
25 var strategy = new Array(
26 new Array('Cheap', 'I\'m Really Cheap'),
21 new Array('Stingy', 'I\'m Pretty Stingy'),
28 new Array('Conservative', 'I\'m Conservative'),
29 new Array('Moderate', 'I\'m a Moderate'),
30 new Array('Agressive', 'I\'mAggressive'),
31 new Array('Wil1ing to sell mother', 'I\'d Sell My Mother! ' )
32 ):
33
34 var background = new Array(
35 new Array(imagePath + 'goldthumb.gif', 'Gold Bars'),
36 new Array(imagePath + 'billsthumb.gif', 'Dollar Bills'),
37 new Array(imagePath + 'fistthumb.gif', 'Fist of Cash'),
38 new Array(imagePath + 'currencylthumb.gif','Currency l'),
39 new Array(imagePath + 8currency2thumb.gif','Currency 2')
40 );
41
42 var face = new Array(
43 new Array('times', 'Times Roman'),
44 new Array('arial', 'Arial'),
45 new Array('courier', 'Courier New'),
46 new Array( 'tahoma', 'Tahoma')
41 1;
48
49 var size = new Array(
50 new Array('lO', 'Small'),
51 new Array('l2', 'Medium'),
52 new Array('l4', 'Large'),
Preferencias del usuario basadas en cookies 237
92 I
93 return '<SELECT NAME="' + name + + (onChangeStr ? '
I " '
onchange=" +
94 onChangeStr + : ") + + optStr + '</SELECT>';
' > I
95 1
96
97 function genBoxes(handle, arrObj) I
98 var boxStr = " ;
99 for (var i = 0; i c arrObj.length; i++) I
100 boxStr += '<INPUTTYPE=CHECKBOX NAME="' + handle + i +
VALUE=" +
238 Preferencias del usuario basadas en cookies
101 arrObj [il L O 1 + ' , ' + arrObj[i] [11 + "'> ' + arrObj[il L O 1 +
* <BR> ' ;
102 1
103 return boxStr;
104 J
105
106 function getPrefs(form0bj) {
107 var prefStr = GetCookie('userPrefs');
108 if (prefStr = = null) { return false; 1
109 var prefArray = prefStr.split('-->');
110 for (var i = 0; i < prefArray.length; i + + ) {
111 var currPref = prefArray[il.split('::'):
112 if (currPref[ll == "select") {
113 formObj[currPref[Ol].selectedIndex = currPrefL21;
114 1
115 else if (currPref[l] == "text") {
116 formObj[currPref[O]].value = currPrefL21;
117 1
118 else if (currPref[lI == "checkbox") {
119 formObj [currPref[Ol I .checked = true:
120 I
121 I
122 return true;
123
124
125 function setprefs formobj) {
126 var prefStr = '
127 var htmlStr = '
128 for (var i = 0; i < form0bj.length; i++) {
129 if (formObj[i .type == "select-one") {
130 prefStr += formObj [i].name + '::select::'+
131 formObj[il.selectedIndex + ' - - > I ;
140 1
141 else if (formobj[il .type == "checkbox" & & formObj [il .checked)
I
142 prefStr += formObj[il.name + '::checkbox::'+ ' - - > ' ;
143 htmlStr += formObj[il.narne + ' = ' + formObj[il.value + ' -
>';
144 1
Preferencias del usuario basadas en cookies 239
155 )
156
157 function populateForm(form0bj) {
158 if (getPrefs(form0bj) {
159 makePath(form0bj);
160 swapImage('bkgImage',
161 form0bj.background.options[formObj.background.selectedIndexl
.value);
162 1
163 else { resetImage(document.forms[Ol); 1
164 )
165
166 function resetImage(form0bj) {
167 swapImage('bkgImage',form0bj.background.options[0l.value);
168 swapImage('fontImage',imagepath +
formObj .face.options[Ol.value +
169 formObj.size.options[O].value + '.gif');
170 }
171
172 </SCRIPT>
173 < /HEAD>
174
175 <BODY BGCOLOR=FFFFFF onLoad="populateForm(document.forms[O]);">
176 < DIV ID= " sett ing " >
177 cH21Take-A-Dive User Preferences</H2>
178 Choose the settings you like best, then choose<BR>
179 <UL>
180 <LI><B>Save</B> to keep your changes,
181 <LI><B>Clear</B>to reset the form, or
182 <LI> <B>Back</B> to return to your links page.
183 </UL>
184
185 <FORM>
186 <TABLE BORDER=l CELLBORDER=O CELLPADDING=O CELLSPACING=l>
187 <TR>
188 <TD COLSPAN=2>
189 <BR>
190 <H3>Investor Profile</H3>
191 </TD>
192 </TR>
193 <TR>
240 Preferencias del usuario basadas en cookies
194 <TD>Name<lTD>
195 <TD><INPUT TYPE=TEXT NAME="investor"></TD>
196 </TR>
197 <TR>
198 <TD>Age</TD>
199 <TD><INPUT TYPE=TEXT NAME="age"></TD>
200 </TR>
201 <TR>
202 <TD>Strategy</TD>
203 <TD>
204 <SCRIPT LANGUAGE="JavaScriptl.2">
205 document.write(genSelect('strategy', 3)1 ;
206 </SCRIPT>
207 < /TD>
208 </TR>
209 <TR>
210 <TD>Occupation</TD>
211 <TD>
212 <INPUT TYPE=TEXT NAME="occupation> 'I
213 </TD>
214 <TR>
215 <TD COLSPAN=2>
216 <BR>
217 <H3>Investment Links</H3>
218 </TD>
219 </TR>
220 <TR>
221 <TD><B>News<B></TD>
222 <TD>
223 <SCRIPT LANUAGE="JavaScriptl.2">
224 document.write(genBoxes('newsNames')) ;
225 </SCRIPT>
226 </TD>
227 </TR>
228 <TR>
229 <TD><B>StockIndexes</B></TD>
230 <TD>
231 <SCRIPT LANUAGE="JavaScriptl.2">
232 document.write(genBoxes('indexNames'));
233 </SCRIPT>
234 </TD>
235 </TR>
236 <TR>
237 <TD COLSPAN=2>
238 <BR>
239 <H3>Screen Layout</H3>
240 </TD>
241 </TR>
242 <TR>
243 <TD>
244 <B>Background</B>
Preferencias del usuario basadas en cookies 241
245 <BR>
246 <SCRIPT LANGUAGE="JavaScriptl.2">
247 document.write(genSelect('background',0 ,
248 swapImage( bkgImage ' ,
249 this.options[this.selectedIndexl .value)")1 ;
250 </SCRIPT>
251 </TD>
252 <TD>
253 <IMG SRC="images/blank.gif"
254 NAME= bkgImage WIDTH=112 HEIGHT=6O >
'I 'I
255 </TD>
256 </TR>
257 <TR>
258 <TD>
259 <B>Font Face</B>
260 <BR>
261 <SCRIPT LANGUAGE="JavaScriptl.2">
262 document.write(genSelect('face', 0,
"makePath(this.form)" ) ) ;
263 </SCRIPT>
264 < /TD>
265 <TD ROWSPAN=2>
266 <IMG SRC="images/blank.gif"NAME="fontImage"
267 WIDTH=112 HEIGHT=60>
268 </TD>
269
270 </TR>
271 <TR>
272 <TD>
273 <B>Font Size</B>
274 <BR>
275 <SCRIPT L A N G U A G E = " J a v a S c r i p t 1 . 2 " >
276 document.write(genSelect('size', 0,
"makepath(this.form)" ) ) ;
277 </SCRIPT>
278 </TD>
279 </TR>
280 </TABLE>
281 < BR><BR>
282 <INPUT TYPE=BUTTON VALUE="Save" onClick="setPrefs(this.form); " >
283 <INPUT TYPE=RESET VALUE="Clear" onClick="resetImage(this.form); " >
284 <INPUT TYPE=BUTTON VALUE="Back"
onClick="location.href='dive.html';">
285 < ! - -
286 <INPUT TYPE=BUTTON VALUE="Show"
287 onClick="alert(GetCookie('userPrefs'));alert(GetCookie
('htmlPrefs'));">
288 <INPUT TYPE=BUTTON VALUE= "Erase"
289 onClick="DeleteCookie('userPrefs');
DeleteCookie('htmlPrefs');">
290 / / - - >
242 Preferencias del usuario basadas en cookies
291 </FORM>
292 </DIV>
293 </BODY>
294 </HTML>
Las lineas 10-68 son bastante curiosas. En vez de identificar la ruta donde se
encuentran las imagenes (linea lo), sus variables se dedican a configurar el di-
sefio de dive.htrnZ. A cada una de ellas, se le asigna el valor de un array de varias
dimensiones. Es decir, de un array de arrays.
Por ejemplo, a continuacion podemos ver un array que consta de una unica
dimension:
var twoDimension =
new Array (
new Array(1,2,3),
new Array ( 4 , 5 , 6 ) ,
new Array (7,8,9 )
);
Tal y como indica el tCrmino array multidimensional, cada elemento del array
es un array de dos elementos. Basicamente, un elemento contiene la cadena que
se mostrara en la pantalla y el otro la cadena que se encargara del trabajo que se
ejecutara en el segundo plano. Por ejemplo , s i z e [ 0 I [ 0 I es igual a 10. Este va-
lor se usara para establecer el tamafio, en pixeles, de la fuente. Pero, s i z e [ 0 1 [ 1I
es igual a Small, que es la descripci6n que aparecera en la pantalla. A 10s usua-
rios les resultara mas sencillo asociar el tamafio de la letra a travks de "small"
(pequefio) que del valor 10. En el resto de arrays el funcionamiento es practica-
mente el mismo.
Las lineas 56-57 no son otra cosa que llamadas a1 metodo s o r t ( ) del objeto
Array para que ordene 10s indices bursatiles y 10s enlaces de noticias. No es ne-
cesario, pero un par de lineas mas no molesta a nadie. El archivo prefs.html uti-
liza una serie de graficos, por lo que seria conveniente cargarlos de nuevo. Las
lineas 70-73 se encargan de ello:
Vamos a centrarnos en el codigo HTML que se encuentra situado entre las li-
neas 174-294. El codigo se encuentra en el ejemplo 7.1 .
document.write(genSelect('strategy', 3 ) ) ;
Despub de repetir esta acci6n con todos 10s elementos de strategy y de cons-
truir optStr con todas las etiquetas OPTION, una sencilla suma (que tiene lugar
en las lineas 93-94) se encarga de colocar todas las etiquetas OPTION con las res-
pectivas SELECT.
Y iqut ocurre con el tercer argumento que se deberia recibir, tal y como se ha
definido en genselect ( ) ? A estos elementos se les llama onChangeStr y no se
utilizan en esta llamada. Per0 lo verernos en otras ocasiones, por ejemplo en las
lineas 247-249:
246 Preferencias del usuario basadas en cookies
document.write(genSelect('background',0 ,
swapImage ( ' bkgImage ,
this.options[this.selectedIndexl.value)")
);
function genBoxes(name) {
var boxStr =
var arrObj = eval(name);
for (var i = 0; i < arr0bj.length; i++) {
boxStr += '<INPUT TYPE=CHECKBOX NAME="' + handle + i + VALUE="' +
' I '
arrObj[i] [ O ] + ' , ' + arrObj [il 111 + "'> ' + arrObj[il [O] + '<BR>'
1
return boxStr;
1
function populateForm(form0bj) {
if (getPrefs(form0bj)){
Preferencias del usuario basadas en cookies 247
makePath(form0bj):
swapImage('bkgImage',form0bj.background.options
[formObj.background.selectedIndex].value):
1
else { resetImage(document.forms[O]): }
function getPrefs(form0bj) {
var prefStr = GetCookie('userPrefs'):
if (prefstr == null) { return false: )
var prefArray = prefStr.split('-->'):
for (var i = 0 ; i < prefArray.1ength: i++) {
var currPref = prefArray[il.split('::'):
if (currpref[l] == "select") {
formObj[currPref[O]].selectedIndex = currPref[21:
}
else if (currpreflll == "text") {
formObj[currPref[Oll.value = currPref[21:
1
else if (currpref[l] == "checkbox") {
formObj[currPref[0ll.checked = true:
1
1
return true:
1
getprefs ( ) tambien tiene que tomar una decision. Funciona asi: obtiene la
informacion que se encuentra dentro del archivo cookie que estC asociado con el
nombre userprefs. Si el valor es cero, devolvera false.Es decir, que aun no se
habra establecido la propiedad document.cookie de userPrefs. Per0 si userPrefs
no es igual a cero, entonces habra alguna configuracion. En nuestro ejemplo con-
creto, userPrefs es igual a cero, per0 conviene repasar quC ocurre cuando userPrefs
contiene informacion.
Si userPrefs contiene la informacion deseada, getprefs ( ) crea u n array divi-
dendo el valor de prefStr utilizando el separador que se haya acordado para unir
cada uno de 10s elementos de la configuracion de setprefs ( ) . L a cadena es - ->.
248 Preferencias del usuario basadas en cookies
Ahora, 10s elementos de prefsArray contienen una cadena separada por : : que
indica el tip0 del elemento y el valor que tiene asociado. Para asignar 10s valores
asociados a 10s elementos no hay mas que repetir la ejecuci6n de la funcion a
traves de 10s elementos prefsArray y asignar cada uno de ellos de acuerdo con la
clase del elemento del formulario. La verdad es que las lineas 110-12 1 lo expli-
can bastante mejor:
Del mismo mod0 que el buclefor de la linea 110 se ejecuta con todos 10s ele-
mentos de prefsArray, el valor de la variable local c u r r p r e f sera un array que
Preferencias del usuario basadas en cookies 249
estara dividido por pref sArray [ i 1 cada vez que aparezcan 10s simbolos : :. Es
decir, que currPref tendra tres elementos (dos para las casillas de verificacion).
Como currpref [ 1I contiene el identificador de tip0 para el elemento del formu-
lario, a1 activarlo se determinara quC hace la getpref s ( ) con curpref [ 0 I y
currpref [ 2 1 .
Si currPref [ 11 es igual a select, getpref s ( ) utiliza la linea 113 para asignar
la lista de seleccion nombrada en currpref [ 0 I , a la opcion que esta asociada
con selectedlndex en currpref [ 2 1 . En realidad es parseInt (currpref[ 2 3 ) ,
per0 como JavaScript lo conoce, convierte la cadena en un numero.
Si currPref [ 1 3 es igual a t e x t , getpref s ( ) utilizara la linea 116 para asig-
nar a1 campo de texto a quiCn se hace referencia en currpref [ 0 I , el valor de
currPref [2I .
Y por ultimo, si currpref [ 1 1 es igual a checkbox, getpref s ( ) trabajara con
la linea 119 para asignar a la propiedad checked de checkbox de currpref [ 0 I ,
a true. En este caso no habra currpref [ 2 ] . Si la informacion que se encuen-
tra en el archivo cookie contiene la casilla de verificacion, Csta sera la unica in-
dicacion que se utilizara.
Esto que hemos visto se repite con cada elemento de prefshray. En el momento
en que se termina, el usuario tendra un formulario que reflejara la informacion
de su ultima configuracion. Por lo tanto, getpref s ( ) habra completado su tra-
bajo y devolvera el valor true para indicar apopulateForm ( ) que lo completo
satisfactoriamente.
makePath(form0bj);
swapImage('bkgImage',
formObj.background.options[formObj.background.selectedIndexl .value);
mas sencillo de 10s dos, la llamada a swapImage ( 1 . Una vez que sabemos que
swapImage ( ) espera un par de argumentos, que se le entregaran en las lineas
160-161, miraremos el c6digo de las lineas :
formObj.background.options[formObj.background.selectedIndexl.value
Ya tenemos la imagen del fondo. iQuC hay del grafico? Es algo mas complica-
do. Con ella tendremos una imagen de la secuencia que sera la que se utilice
para reflejar la opcion seleccionada. Con la imagen de la fuente, aun teniamos
una imagen que se podia utilizar en la secuencia, per0 Csta se basaba en las eti-
quetas OPTION de las dos listas de seleccion. Vamos a ver como se crea el URL de
las imagenes. La tabla 7 . 3 muestra 10s valores de OPTION y el texto correspon-
diente de las dos listas de seleccion.
Tabla 7.3. Opciones correspondientesa la familia y tamaiio de la fuente
Vamos a ver quC ocurre cuando se combinan 10s valores de OPTION. Veamos
todas las combinaciones posibles.
function makePath(form0bj) (
var fontName = imagepath +
formObj.face.options[formObj.face.selectedIndex~.value +
formObj.size.options[formObj.size.selectedIndexl.value + '.gif';
swapImage ("fontIrnage", fontName) ;
1
252 Preferencias del usuario basadas en cookies
makepath ( ) acepta una copia del objeto del formulario como argumento. Se
trata de f ormObj cuyas referencias hemos visto ya en las dos etiquetas OPTION
seleccionadas. A continuacion se afiade .gv. Ahora, la variable f ontName sera
una cadena que apunta a la imagen correcta. La llamada a swapImage ( 1 que
tiene lugar en la linea 79 se encarga de todo. Obviamente, estamos dando por su-
puesto que el usuario ya ha establecido algun tip0 de preferencias con anterio-
ridad. SigetPrefs ( devuelve false,en la linea 163populateForm() llamara
a la funcion resetImage ( ) para que se haga cargo de la secuencia de las ima-
genes de fondo, que estan asociadas con la etiqueta O P T I O N 0 de las listas de se-
leccion de fondo y de fuente. En la proxima seccion veremos mas detalles.
Vamos a recapitular lo que hemos visto:
Efectuar cambios
Ahora el usuario tiene en pantalla las opciones que selecciono la ultima vez.
Vamos a ver quC pasa si quiere establecer algun cambio.
Al usuario le resultara muy sencillo modificar el contenido de la pagina. Se li-
mitara a introducir informacion en 10s campos de texto o seleccionar alguna
opcion de las listas. Cuando termine, hara clic en el boton "Save".En este momen-
to sera cuando empiece nuestro trabajo. Vamos a ver el cbdigo que se esconde
detras del b o t h "Save" en la linea 2 8 2 :
Pare muy tipico. Llama a la funcion setpref s ( ) y pasa una copia del formu-
lario en forma de argumento. L o divertido comienza en las lineas 125-151:
function setPrefs(form0bj)
var prefStr = " ;
var htmlstr = " ;
for (var i = 0; i < form0bj.length; i++) (
if (formObj[il .type == "select-one") I
prefStr += formObj[i].name + '::select::' + formObj[i].
selectedIndex + ' - - > ' ;
htmlStr += formObj[i].name + ' = ' + formObj[il.options[formObj[i].
Preferencias del usuario basadas en cookies 253
1
else if (formObj[i].type == "text") {
if (formObj[il.value == " ) { formObj[il.value = "Not Provided";
1
prefStr += formObj[il.name + '::text::' +
safeChars(formObj[i].value) + I - - > ' ;
1
else if (formObj[i].type == "checkbox" && formObj [i].checked) {
prefStr += formObj[i].name + '::checkbox::' + ' - - > I ;
}
1
SetCookie('userPrefs',prefStr, expiry);
SetCookie('htmlPrefs', htmlstr, expiry);
if (confirm('Preferenceschanged. Go to your personalized page?')) {
self.location.href = "dive.htm1";
1
1
1
else if (formObj [il .type == "text") (
i f (formObj[il.value == " ) { formObj[i].value = "Not Provided"; 1
prefStr += formObj[i].name + '::text::' +
safeChars(form0bj [i].value) + ' - - > I ;
1
else if (formObj [il .type == "checkbox" & & formObj [i].checked) {
prefStr += formObj[i].name + '::checkbox::' + ' - - > ' ;
htmlStr += formObj[i].name + ' = ' + formObj[i].value + ' - - > I ;
Una de las propiedades de 10s elementos del formulario con la que se esta tra-
bajando es type, que contiene una cadena la cual identifica el tip0 de elemento.
setpref s ( ) solo tendra que localizar a uno de ellos: texto, casilla de verifica-
cion u opcion de una lista. La composicion de la declaracion i;f que hemos visto
en el codigo anterior desarrolla una acci6n distinta para cada tip0 de accion.
Independientemente del tipo, se ejecutara setpref s ( ) de una de estas formas:
Suma el nombre del elemento del formulario, la cadena equivalente a1 tip0
del elemento y posiblemente, el valor o el indice seleccionado. Entre ellos se
colocara un separador.
A dicha cadena le suma un valor existente de prefstr y de htmlstr.
function safeChars(str) {
return str.replace(/::I=l-->/g, .,
# . . I 1;
1
Preferencias del usuario basadas en cookies 255
investor=Not Provided-->age=Not
Provided-->strategy=Moderate-->occupation
=Not Provided-->newsNamesO=Barron's Online,http://www.barrons.com/-->
newsNamesl=CNN Interactive,http://www.cnn.com/--~newsNames2=FoxNews,
http://www.foxnews.com/-->newsNamesl=The Wall Street Journal,
http://www.wsj.com/-->indexNamesO=DowJones Indexes,
http://www.dowjones.com/-->indexNamesa=TheNew York Stock Exchange,
http://www.nyse.com/-->background=images/fistthumb.gif-->face=tahoma-->
size=14-->
Por otro lado, MSIE 4.x15.x, guarda la informacion de cada cookie dentro de
un archivo independiente. Los nombres de dichos ficheros se corresponden con
el del dominio de donde procede la informacion y con el nombre del usuario que
determino las preferencias. Este es un extracto del contenido de 10s archivos
cookie que tengo en mi sistema WinNT . Estoy registrado como administrador.
Cookie:administrator@altavista.com
Cookie:administrator@amazon.com
Cookie:administrator@builder.com
Cookie:administrator@cnn.com
Cookie:administrator@dejanews.com
Cookie:administrator@hotbot.com
Cookie:administrator@infoseek.com
Es parte de la finalidad de prefxhtrnl. Per0 aun hay u n elemento mas que casi
siempre se suele olvidar: borrar el formulario.
Borrar el formulario
LNo podriamos tener u n boton <INPUT TYPE=RESET> que se encargase de esto?
Pues si. Un boton que se encargue de asignar a 10s campos de texto una cadena
Preferencias del usuario basadas en cookies 257
function resetImage(form0bj) {
swapImage('bkg1mage'. form0bj.background.options[01 .value);
swapImage('fontImage', imagepath + formObj.face.options[Ol .value +
formObj.size.options[Ol.value + '.gif');
}
Se trata de una funcion que invoca a otra funcion. En realidad, llama dos veces
a swapImage ( ) . Con la primera llamada cambia la imagen del fondo y utiliza
la imagen que se encuentra asociada a OPTION 0, la cual tambikn es conocida
como f ormObj .background. opt ions [ 0 I .value.En la siguiente llamada hace
otra vez lo mismo, per0 crea la ruta de la imagen asociada a OPTION 0. Se pa-
rece a makepath ( ) , resetImages ( ) establece el URL de la imagen valitndose
de la variable imagepath, 10s valores OPTION correspondientes a las dos listas
relacionadas con las fuentes (solo que en esta ocasidn se utiliza el 0 en lugar de
sekctedlndex), seguido de la cadena .g$ Con estas dos llamadas reiniciamos el
valor de las dos imageries.
Y con esto terminados de repasar todas las funciones de prefs.htm2. Vamos a
pasar ahora a dive.htm1.
dive.html
Las preferencias del usuario han cambiado. Ha llegado el momento de conver-
tir esos cambios en una realidad visual. El proceso no es demasiado largo, per0
lo detalles nos pueden dar algun dolor de cabeza. Parece obvio que la informa-
cion que se utilice procedera del archivo cookie. Esta informacion se utilizara de
tres formas distintas.
Ejemplo 7.2.dive.htm1
1 <HTML>
2 <HEAD>
3 <TITLE>
4 Your Take-A-Dive Links Page
5 </TITLE>
6 <SCRIPT LANGAUGE='' JavaScript1.2 SRC= cookies.js >< /SCRIPT>
I' 'I
7 <SCRIPT LANGUAGE="JavaScript1.2">
8 <!--
9
10 var newsNames = new Array ( ) ;
11 var indexNames = new Array();
12
13 function getAttributes0 (
14 var htmlStr = GetCookie('htm1Prefs');
15 if (htmlStr == null) {
16 alert('We1come. You must first set your user preferences.' +
17 'Please choose OK to load the User Settings page.');
18 self.location.href = 'prefs.htm1';
19 1
20 var htmlArray = htmlStr.split('-->') ;
21 for (var i = 0; i < htmlArray.length; i++) {
22 var tagInfo = htmlArray[il .split('=');
23 if (tagInfo[Ol ! = '"') {
24 if (tagInfo[O].indexOf('newsNames')== 0 ) {
25 newsNames[newsNames.lengthl = tagInfo[ll;
26 1
27 else if (tagInfo[O].indexOf('indexNames')== 0 ) {
28 indexNames[indexNames.lengthl = tagInfo[ll;
29 }
30 else eval(tagInfo[Ol + ' = " ' + tagInfoLl1 + ""); 1
31 1
32 }
33 1
34
35 getAttributes0;
36
37 function genLinks(1inkArr) {
38 var linkStr = " ;
39 for (var i = 0; i < 1inkArr.length; i++) {
40 var linkparts = linkArr[il.split(',' )
41 linkStr += ' - <A HREF="' + linkParts[ll + "'> '
42 + linkParts[O] + '</A><BR>'
43 1
44 return linkstr;
45 1
46
Preferencias del usuario basadas en cookies 259
47 //-->
48 </SCRIPT>
49 <SCRIPT LANGUAGE="JavaScriptl.2">
50 document.write('<STYLEtype="text/css"> TD ' +
51 { font-family: ' + face + ' ; font-size: ' + size + 'pt; )
</STYLE>');
52 </SCRIPT>
53 </HEAD>
54 <SCRIPT LANGUAGE="JavaScript">
55 document.write('<BODYBACKGROUND="' +
56 background.replace(/thumb/, " " ) + "'>' ) ;
57 </SCRIPT>
58 <TABLE BORDER=O>
59 <TR>
60 <TD VALIGN=TOP COLSPAN=I>
61 <H2>Take-A-Dive Brokerage $ervices</H2>
62 </TD>
63 </TR>
64 <TR>
65 <TD VALIGN=TOP COLSPAN=4>
66 Take-A-Dive Brokerage Services is dedicated to helping YOU
part with
67 your MONEY. <BR> Our motto is "<I>We go for broke.</I>"
68 Here is your user profile
69 and your customized links.
70 <BR><BR>
71 </TD>
12 </TR>
73 <TR>
74 <TD VALIGN=TOP>
75 Name:</TD>
76 <TD VALIGN=TOP>
77 <SCRIPT LANGUAGE="JavaScriptl.2">document.write(investor)
</SCRIPT>
78 <TD VALIGN=TOP>
79 </TD>
80 Age :
81 <TD VALIGN=TOP>
82 <SCRIPT LANGUAGE="JavaScriptl.2"~document.write(age)
</SCRIPT>
83 </TD>
84 </TR>
85 <TR>
86 <TD VALIGN=TOP>
87 Strategy:
88 </TD>
89 <TD VALIGN=TOP>
90 <SCRIPT LANGUAGE="JavaScriptl.2">
91 document.write(strategy);
92 </SCRIPT>
93 </TD>
260 Preferencias del usuario basadas en cookies
94 <TD VALIGN=TOP>
95 Occupation:
96 </TD>
97 < T D VALIGN=TOP>
98 <SCRIPT LANGUAGE="JavaScript1.2">
99 document.write(occupation);
100 </SCRIPT>
101 < / TD>
102 </TR>
103 <TR>
104 <TD VALIGN=TOP COLSPAN=2>
105 <BR><BR>
106 News Links<BR>
107 <SCRIPT LANGUAGE="JavaScriptl.2" >
108 document.writeln(genLinks(news));
109 </SCRIPT>
110 <TD VALIGN=TOP COLSPAN=2>
111 <BR><BR>
112 Stock Index Links <BR>
113 <SCRIPT LANGUAGE="JavaScript1.2">
114 document.writeln(genLinks(indexes) ) ;
115 </SCRIPT>
116 </TD>
117 </TR>
118 <TR>
119 <TD VALIGN=TOP COLSPAN=2>
120 <BR><BR>
121 [ <A HREF="prefs.html">Set Preferences</A> I
122 </TD>
123 </TR>
124 </TABLE>
125 </BODY>
126 < / n T m >
function getAttributes0 {
var htmlstr = GetCookie('htm1Prefs');
if (htmlstr == null) {
Preferencias del usuario basadas en cookies 261
if (tagInfo[O].indexOf('news')== 0 ) {
newsNames[newsNames.lengthl = tagInfo[ll;
1
else if (tagInfo[O].indexOf('indexes')== 0 ) (
indexes[indexNames.lengthl = tagInfo[ll;
}
else ( eval(tagInfo[O] + ' = " ' + tagInfo[ll + ""); 1
1
1
262 Preferencias del usuario basadas en cookies
El texto que aparece en negrita representa el nombre de las variables que defi-
niremos en un momento. El buclefor de getAttributes ( ) acomoda la asigna-
ci6n a 10s elementos del array y la declaracion de las variables que se desconocen.
Lo podemos ver en 1as lineas 22-3 1:
Cada elemento de htrnZilrray contiene un signo igual (=) que separa el iden-
tificador de su valor. Con cada repetition del buclefor, se ejecuta la funcion split ( )
para que divida a htmlArray [ i 3 por cada signo igual, y sus dos sub-array de
dos elementos se asignan a la variable local taglnfo. Si tagInf o [ 0 I no es igual
a una cadena vacia, tendremos un par identificador-valor valido. La comproba-
ci6n de si la cadena esta vacia se debe a la forma en que JavaScript devuelve el
resultado de split ( 1 .
Cada uno de 10s pares identificador-valor pertenecera a una de estas dos cate-
gorias: un elemento array o una variable ordinaria. Si nos encontramos con el
primer caso, tambiCn tendremos dos posibilidades: contiene un nuevo enlace o
un vinculo a1 indice bursatil. La siguiente declaracion if-else determina la accion
que se desarrollara en dichas circunstancias:
if (tagInfo[O].indexOf('newsNames') == 0 ) I
newsNames[newsNames.length] = tagInfo[ll;
1
else if (tagInfo[O].indexOf('indexNames') == 0 ) (
indexNames[indexNames.~ength]= tagInfo[ll;
1
else { eval(tag~nfo[o] + ' = " ' + tagInfo[ll + ""); 1
que asociar con 10s indices bursatiles. Por lo tanto, tagInf o [ 1] pasara a1 siguien-
te elemento de indexNarnes. Si tagInfo [ 01 tampoco contiene una cadena, en-
tonces tagInfo [ 0 I y tagInfo [ 1] habran de contener el nombre de la variable
que se va a declarar y el valor que se le asignar8. El c6digo de la linea 30 sabe quC
ha de hacer:
eval(tagInfo[o] + ' = ' I ' + tagInfo[ll + " " ) ;
Aunque las llamadas 3-6 se explican por si solas, no ocurre lo mismo con las
dos primeras. Vamos a empezar por las lineas 50-51:
Esta llamada escribe una hoja de estilo en la pagina, pero insertara las variables
de estilo que se encargan del tipo y tamaiio de las fuentes.
Una vez que tenemos la hoja de estilo que acabamos de crear sobre la marcha,
trataremos de conseguir la imagen que se utilizara como fondo. Lo tenemos en
la linea 55-56:
function genLinks(1inkArr) {
var linkStr = " ;
for (var i = 0; i < 1inkArr.length; i++) {
var linkparts = linkArr[i].split(', ' )
linkStr += ' - <A HREF="' + linkParts[ll + "'> ' +
linkParts[O] + ' < / A > < B R > '
1
return linkStr;
1
Posibles aplicaciones
Con un poco de creatividad se puede sacar mucho provecho de esta aplicacion.
Aqui tenemos unas cuantas posibilidades:
Agregar campos para manipular el color de fondo de las celdas de una tabla
y otros elementos de la composici6n.
Permitir que 10s usuarios seleccionen u n tema para las paginas.
Aiiadir un par de campos de texto adicionales con la finalidad de que el
usuario pueda agregar la direcci6n de sus paginas Web favoritas (con
nombres).
Publicar anuncios de acuerdo a las preferencias del usuario que se han re-
gistrado en las cookies.
268 Preferencias del usuario basadas en cookies
Aiiadir temas
Esta idea procede de 10s temas del escritorio de Windows 95. En vez de dejar
que 10s usuarios seleccionen un tema para cada elemento de la composicion,
ipor qut no dejar que seleccione un par de temas que se encarguen de la confi-
guracion de todos 10s elementos de la composicion? Supongamos que tenemos
un sitio Web relacionado con el mundo de la musica. Podriamos trabajar con la
siguiente lista:
<SELECTNAME="themes"onChange="swapImage('theImage',
this.options[this.selectedIndexl.value);"~
<OPTION ~ ~ ~ ~ ~ = " n o n e " > N o n e
<OPTION VALUE="bigband">BigBand
<OPTION VALUE="rocknroll">Rock ' n Roll
<OPTION VALUE="rap">Rap
<OPTION VALUE= " country">Country
<OPTION VALUE="reggae">Reggae
<OPTION VALUE="grunge">Grunge
<OPTION VALUE="jazz">Jazz
<OPTION VALUE="club">Club Music
< f SELECT>
Cada uno de estos valores de OPTION podria estar relacionado con una minia-
tura de una imagen. Podemos utilizar genselect ( ) y swapImage ( ) deprefs.htmZ
para crear la lista y encargarnos de las secuencias de imagenes. No olvidemos
que a1 seleccionar uno de estos temas, tendremos que permitir que se puedan
desactivar 10s elementos de la composicion individualmente, como por ejemplo,
la imagen del fondo o el aspecto de la fuente. Obstrvese que la primera OPTION
muestra "None" en pantalla. Conviene incluir esta opci6n para que el usuario
pueda seleccionar las opciones que desee.
<TD><B>Extra Links</B></TD>
<TD>
<INPUT TYPE=BUTTON VALUE=" Add " onClick="addOpt(this.form);">
<INPUT TYPE=BUTTON VALUE="Delete"
onClick="deleteOpt(this.form); " >
</TD>
</TR>
<TR>
<TD>Link Name</TD>
<TD><INPUT TYPE=TEXT NAME="linkname" SIZE=20></TD>
</TR>
<TR>
<TD>Link URL</TD>
<TD><INPUT TYPE=TEXT NAME="linkURL" SIZE=20></TD>
</TR>
</TABLE>
Si en este libro hay una aplicacion que sea realmente robusta, es la que vere-
mos en este capitulo. Con Shopping Bag unicamente necesitaremos las ilustra-
ciones y descripciones de 10s elementos que apareceran en nuestro sitio Web. No
habra que crear ningun archivo adicional. Shopping Bag lo hara por nosotros
sobre la marcha. Tampoco necesitaremos 10s servicios de un servidor que se en-
cargue de calcular 10s impuestos y el valor total de la compra. De esto tambien
se encargara Shopping Bag. El usuario podra agregar y eliminar productos de
su carro de la compra con un sencillo clic. A diferencia de lo que ocurre en el su-
permercado, con este carro de la compra no tendremos que esperar colas.
1 . Se carga la aplicacion.
2. El comprador revisa las categorias de 10s productos o busca uno determi-
nado. Mientras, puede agregar a su carro de la compra todos 10s que desee.
3 . Segun el contenido del carro, el comprador podra revisar 10s articulos se-
leccionados y modificar su contenido o cantidad.
4. Cuando este de acuerdo con su seleccion, podra pagar lo que ha comprado.
2 72 Shopping Bag: un carro de la compra en JavaScript
Esta aplicaci6n tambitn establece una serie de reglas que ha de cumplir Shopping
Bag. Las iremos viendo en las secciones donde se tengan que aplicar. Vamos a
ver 10s pasos del proceso.
I'
~-~__----.. -__ .-_____I_
i-r-"~m----~-'
Figura 8 . 1 . Paritalla de inicio de Shopping Bag
Aun admirado por nuestras ofertas, nuestro cliente decide utilizar la propie-
dad de busqueda. Selecciona el vinculo "Product Search" y accede a la pantalla
que recoge la figura 8.4. Nuestro cazador de ofertas introduce la cantidad "1.15"
en el campo de busqueda para localizar productos con ese precio. La aplicacion
revisa el precio de todos 10s productos de su base de datos y muestra una lista
con cinco de ellos, tal y como se puede observar en la figura 8.5. Un secador de
pelo (hairdryer), una corbata (necktie) y otros productos, todos con un precio
de 1.15. Revisa las patatas fritas (fries),le gustan y las aiiade tambikn a la bolsa
de la compra.
Nuestro comprador decide regresar a la pantalla donde se muestran todas las
categorias, asi que hace clic en el vinculo "Show All Categories". Esta vez, entra
en la seccion de ropa (clothing). Sigue 10s vinculos y encontrara que la corbata
tiene un precio increible, 1.15, asi que la incluye en la bolsa de la compra.
Figura 8.4. Aqui empieza la bhsqueda de productos
Aun encantado con 10s iglus, nuestro cliente cambia la cantidad de estos produc-
tos que quiere adquirir. Pasa de 1 a 6. Vive en un clima muy caluroso y este tipo
de productos no dura demasiado. Mejor tener de sobra. Las patatas fritas tienen
un aspect0 muy apetitoso, asi que opta por comprar dos paquetes. Pero no tiene
tanto dinero como desearia, asi que opta por olvidarse de la corbata. Siempre
habra una proxima vez.
Regla 3: Los compradores tendran que hacer clic sobre "Change Bag" para
guardar 10s cambios de la bolsa de la compra. Es decir, no pasa nada por
modificar la cantidad de productos o por eliminar alguno de ellos de la bol-
sa de la compra y pasar a otra pantalla.
Shopping Bag: un carro de la compra en JavaScript 277
Es muy sencillo modificar un pedido. Bastara con modificar las cantidades de 10s
objetos solicitados y eliminar 10s que no que quieran, activando la casilla de ve-
rificaci6n que se encuentra en la columna Remove de la tabla. Todos 10s produc-
tos cuentan con una lista desplegable desde donde se podra seleccionar la cantidad
de unidades que se compraran y de una casilla de verificacih "Remove" para
eliminar el product0 del carro de la compra. Despues de modificar el contenido
del pedido, el cliente hara clic sobre "ChangeBag" para ver las cantidades corres-
pondientes a su nuevo pedido (figura 8.7). Ahora su bolsa de la compra mostra-
ra 6 iglus, dos paquetes de patatas y una corbata. Con 10s impuestos, el precio
de la compra asciende a $6,190.5 7.
Paso 4: comprobacion
Cuando el cliente est6 de acuerdo con la compra, hara clic en el vfnculo "Check
Out" con lo que la aplicaci6n abrira el formulario de la figura 8.8. Rellenara la
2 78 Shopping Bag: un carro de la compra en JavaScript
Analisis de la sintaxis
Vamos a echar u n vistazo a1 diagrama de flujo de Shopping Bag. L a figura 8 . 9 .
nos muestra como inicia el usuario las compras, como navega a t r a v b de todos
10s productos, como efectua 10s ultimos cambios, rellena el formulario y 10s en-
via a1 servidor de pedidos.
Esta aplicacion se compone de ocho archivos. En esta lista podemos ver la fi-
nalidad de cada uno de ellos:
index.htmZ. Pagina de inicio de Shopping Bag que controla la ventana de
trabajo.
shopset.htmZ. Marco de trabajo para la ventana remota que se abre a pan-
talla completa. Contiene dos archivos intro.htmZ y rnanager.htmZ.
intro.htmZ. Pagina predeterminada para el marco de trabajo mas grande y
para el documento de ayuda que muestra las funciones de cada una de las
propiedades de la barra de navegacion.
manager.htmZ. Epicentro de Shopping Bag. Toda la funcionalidad procede
de este archivo y sera el centro de estudio de este capitulo.
inventory.js. Contiene funciones, constructores y array para construir el
inventario de Shopping Bag. Gran parte de su trabajo tiene lugar durante
la carga de la aplicacion.
search/index.htmZ. Marco de trabajo donde se carga la aplicacion de bus-
queda de productos. Si hemos leido el contenido del primer capitulo del
libro veremos que se trata de una version de la maquina de busqueda que
se trato entonces.
search/main.htmZ. Pagina de ayuda para el buscador. Se completa con una
serie de ejemplos.
search/nav. html. El cerebro de la aplicacion de busqueda.
Debido a1 tamaAo de la aplicacion y a1 hecho de que ya hemos visto en 10s capi-
tulos anteriores extractos del c6digo de JavaScript que se utiliza para manipu-
lar aplicaciones, en este capitulo vamos a estudiar la aplicacion desde otro punto
de vista.
En vez de avanzar de un archivo a otro, nos moveremos por ellos siguiendo las
cinco operaciones que desarrolla la aplicacion:
1. Cargar Shopping Bag: construye el inventario y carga la pantalla.
2. Mostrar productos: salta de una categoria a otra y de un product0 a otro.
3 . Agregar productos a1 carro de la compra: guarda un registro con todo lo
que se incluye en el carro de la compra.
4. Buscar por productos: establece busquedas basadas en 10s productos del
almackn.
280 Shopping Bag: u n carro de la compra en JavaScript
la aplicacion
a pantalla
completa
I c[>;
Categorias
/as categorias
oroductos
buscar Buscar
Seleccionar
a partir de una
lista de
1 lntroducir
la cadena c
debusqueda
Mostrar (otro)
o categoria
T Navegar
Agregar product0
de revision
de la compra de productos
Si comparamos estas descripciones con las que hemos visto anteriormente con
10s archivos, nos haremos una idea de quk archivos se encargan de quk tarea.
Aun sin estar las cosas muy perfiladas, todo apunta a que la operacion 1 utiliza
codigo de index.htrn1, shopset.htm1 y inventoryjs; en las operaciones 2, 3 y 5 in-
terviene managerhtml; y la operacion 4 es exclusiva de 10s archivos de busqueda.
Aun tenemos el codigo basado en archivos, per0 en breve cubriremos las fun-
ciones de JavaScript que se encargan de cada operacion. Cada una de estas cinco
secciones se describira desde el punto de vista del usuario y de las acciones que
realiza, modificando la cantidad de 10s articulos adquiridos, solicitando ayuda,
etc. Tambikn veremos tkcnicas relevantes. Per0 vamos a empezar por cargar la
aplicacion.
10 <!--
11 var shopwin = null;
12 var positionstr = ; I
13 function whichBrowser0 {
14 if(navigator.appVersion < 4) {
15 alert("You need MSIE 4.x or Netscape Navigator 4.x to use +
16 " Shopping Bag. 'I )
17 return false;
18 I
19 return true;
20
21
22 function launch0 {
23 if(!whichBrowser()) ( return; >
24 if(navigator.appName == "Netscape")
25 { positionstr = ",screenX=O,screenY=O";1
26 else { positionStr = " ,fullscreen=yes"; 1
27 if(shopWin == null) I
282 Shopping Bag: un carro de la compra en JavaScript
function closeupshop ( ) {
if (shopwin ! = null) I
if (typeof(shopwin) == "object") I
shopWin.close0;
1
Shopping Bag: u n carro de la compra en JavaScript 283
1
1
window.onunload = closeUpShop;
Este es el marco de trabajo bAsico. Contiene dos filas. A una se le asigna el co-
dig0 fuente de intro.htrnZ; y la otra la controla rnanager.htm2. Aqui no hay casi
nada de c6digo JavaScript:
function resetopener0 {
opener.shopWin = null;
1
inventory.js
inventory.js contiene tres funciones. Las dos primeras son funciones del cons-
tructor. Una define un producto; la otra define su categoria. L a iiltima funcion
crea un array de objetos 10s cuales crean 10s constructores. Lo podemos ver en el
ejemplo 8 . 3 .
Ejemplo 8.3. inventory.js
1 function product(name, description, price, unit) I
2 this.name = name;
3 this.description = description;
4 this.price = price;
5 this.unit = unit;
6 this.plu = name.substring(0, 3).toUpperCase() +
7 parseInt (price). tostring ( ) ;
8 this.icon = new Image();
9 return this;
10 I
11 function category(name, description) I
12 this.name = name;
13 this.description = description;
14 this.prodLine = eval(name1;
15 var imgDir = images/" + name.toLowerCase( ) + " / " ;
16 for (var i = 0; i < this.prodLine.length; i++) {
17 this.prodLine[i].icon.src= imgDir +
18 this.prodLine[i].name.toLowerCase() + ".gif";
19 1
20 return this;
21 I
22 function makeproducts0 I
23 Appliances = new Array(
24 new product ( "Dryer",
25 "Stylish pastel design, contemporary two-button
engineering.*' ,
26 263.31 ,
27 "each"),
28 new product ( "Hairdryer",
29 "Fancy yellowish blast, and durable cord. No expense
spared. ,
I'
30 1.15,
31 "pair") ,
32 new product ( "Oven",
33 "Made in the 1850's, this coal-powered unit quickly
blackens any" +
34 "favorite dish.",
35 865.78,
36 "each") ,
37 new product ("Radio",
38 "Revolutionary one-channel technology. White noise and
static" +
286 Shopping Bag: un carro de la compra en JavaScript
39 "included." ,
40 15.43,
41 "each") ,
42 new product ("Toaster",
43 "BBQ-style toaster. Only a moderate shock hazard.",
44 25.78,
45 "each") ,
46 new product ( "Washer",
47 "Does a great job on partially everything.",
48 345.61,
49 "each")
50 );
51
52 Buildings = new Array(
53 new product ( "Barn",
54 "Complete with rusty silo and rotting doors. Pig sty sold" +
55 "separately.*I,
56 6350.57,
57 "each") ,
58 new product ( "Lighthouse",
59 "Made of cement. Assorted light bulbs. Three AA batteries '
60 + "not included. 'I,
61 12351.15,
62 "each") ,
63 new product ("Igloo",
64 "Made from top grade snow blocks, and includes a chimney
and +
65 "5-tOn air conditioning unit.",
66 954.76,
67 "each") ,
68 new product ( "City",
69 "Buildings, streets, lights, skyline. Excellent volume
purchase. *' ,
70 334165.95,
71 "each") ,
72 new product ("Castle",
73 "Sturdy medieval design, complete with alligators in moat,
and " +
14 "remote control drawbridge." ,
75 93245.59,
76 "each") ,
77 new product ( "Tower",
78 "Really tall. Ideal for winning friends and spotting forest
I9 " + f ires . " ,
I'
80 24345.87,
81 "pair")
82 );
81
84 Clothing = new Array(
85 new product ( "Bowtie",
86 "Swell red fabric. Doubles a bow for Christmas wreaths or 'I
Shopping Bag: un carro de la compra en JavaScript 287
87 + "birthday gifts." ,
88 5.41,
89 "five"),
90 new product ( "Necktie",
91 "Be the first (and probably only) one (ever) on your block.
92 + "Made of genuine burlap.",
93 1.15,
94 "each"),
95 new product ( "Purse",
96 "Attractive green material. Wards off most mammals.",
97 18.97,
98 "each") ,
99 new product ( "Jacket",
100 "Plush fake fur with fiberglass lining. Washer safe.",
101 180.72,
102 "each") ,
103 new product ( "Glove",
104 "Covers all four fingers and one thumb. Fancy latex
design. " ,
105 6.59,
106 '"three"),
107 new product ("Dress",
108 "Found at a garage sale. Also doubles as a picnic table
cover.'I,
109 7.99,
110 "each") ,
111 new product ( "Watch",
112 "Geuine replica. Doesn't tell time. You have to look at
it.",
113 6.19,
114 "each")
115 );
116
117 Electronics = new Array(
118 new product ( "Camcorder",
119 "Solar-powered. Free microphone. Custom-built for
blackmailing " +
120 "close relatives." ,
121 60.45,
122 each") ,
'I
184 "each"),
185 new product ( "Cycle",
186 "Mow down the wheat field with a few swipes. Just like the
187 + "Grim Reaper ' s . , I'
188 11.15,
189 "each") ,
190 new product ( "Hammer",
191 "Tempered steel head, fiberglass handle. Perfect for
hitting +
192 things. ,
'I
193 9.87,
194 "each"),
195 new product ( "Lawnmower",
196 "Self-propelled (you propel it yourself). " ,
197 165.95,
198 "each") ,
199 new product ( "Pliers",
200 "Perfect for eye brows and nose hairs.",
201 6.59,
202 "each") ,
203 new product ( "Stake",
204 "This 2-in-1 miracle secures tents or gets rid of
vampires." ,
205 3.95,
206 "pair")
207 );
208
209 Music = new Array(
210 new product ( "Bongos",
211 "Great little noise makers for even the most sophisticated
212 '* + "occasions. I , ,
213 35.50,
214 "bongo") ,
215 new product ("Piano",
216 "It ain't grand, but this baby will make you sound like
tavern " +
217 "material in no time." ,
218 1001.40,
219 "each") ,
220 new product ( "Notes",
221 "Choose from A, B, C , D , E, F , or G. Can be reused in any
song.'I,
222 2.97,
223 "note"),
224 new product ( "Guitar",
225 "Strum, strum. This one is your fast track to fame and
fortune. , 'I
226 241.11,
227 "each") ,
228 new product ( "Trumpet",
229 "Solid copper body, and not many dents. Extra spit valve
290 Shopping Bag: un carro de la compra en JavaScript
230 + included. ,
231 683.59,
232 "each")
233 );
234
235 categoryset = new Array(
236 new category "Appliances", "Kitchen machines to make life
eas er") ,
237 new category "Buildings", "Architectural structures your
can t " +
238 "resist"),
239 new category "Clothing", "Fashionably questionable apparel
for +
240 "the 21st century"),
241 new category ( "Electronics", "Nifty gizmos that drain your
wallet"),
242 new category ( " F o o d " , "The best product to order over the
Net"),
243 new category ( "Hardware", "All kinds of general purpose " +
244 "construction tools"),
245 new category("Music", "The hottest new instruments from
places + I'
this.price = price;
this.unit = unit;
this.plu = name.substring(0, 3).toUpperCaseO +
parseInt(price).toStringO;
this.icon = new Image();
return this;
Obskrvese que se han creado seis propiedades, per0 s610 se esperan cuatro ar-
gumentos. El numero de propiedades y el de argumentos que se han de recibir
no coinciden. Vamos a revisar c6mo se asigna a cada propiedad su respectivo
valor. Las cuatro primeras con bastante obvias. A las propiedades name, des-
cription, price y unit se les asigna su correspondiente argumento (aquellos que
coincidan con su nombre).
Per0 plu es otra historia. Se compone de las propiedades name y price. Se utili-
zan las tres primeras letras en mayusculas del nombre del producto y se suma
el precio del producto. Asi, un barco (boat) que cueste $5501.00 tendra una
propiedadplu igual a BOA550 1.No olvidemos que se trata de algo completamen-
te arbitrario. Los productos que se suelen vender ya cuentan con un numero de
referencia. Lo hemos hecho de esta forma para simplificar las cosas. La ultima
propiedad es icon y, de momento, su valor se le ha asignado a a1 objeto Image.
No necesita ningun argumento.
}
return this;
}
Cada una de estas categorias tendra tres propiedades: una cadena llamada name,
otra llamada description y un array llamado prodline. Las propiedades name y
description parecen bastante claras pero, ide donde procede el array y como se
puede utilizar con eval ( ) ? En un momento responderemos ambas preguntas.
De momento vamos a centrarnos en la estrategia basica: siempre que nombre-
mos algo como categoria, se creara un array en la linea de productos con el mis-
mo nombre. Por ejemplo, si creamos una categoria llamada stereos, se creara un
array llamada stereos en donde se guardaran todos 10s productos pretenecientes
a dicha categoria.
No olvidemos que 10s productos tienen una propiedad llamada icon, que es un
objeto Image que no se ha asignado como fuente. Vamos a ver algo mas sobre el
nombre de la categoria. Ya sabemos que todas las categorias guardan su linea
de productos dentro de un array que tiene su mismo nombre. Pues tambien se
guardan dichos productos dentro de un directorio que tiene el mismo nombre
que la categoria.
Todos 10s productos de la categoria Music se guardaran dentro del directorio
music/. Las imagenes correspondientes a la categoria Hardware se encontraran
en el directorio hardware/, etc. Parece un razonamiento logico. Con este sistema,
podremos cargar de antemano 10s productos de la categoria que se est6 constru-
yendo. El codigo de las lineas 16-19 se encarga de ello:
function makeproducts ( ) {
Appliances = new Array(
new prdduct ( "Dryer",
"Stylish pastel design, contemporary two-button engineering.",
263.37 ,
"each") ,
new product ( "Hairdryer",
"Fancy yellowish blast, and durable cord. No expense spared.",
1.15,
"pair") ,
new product ( "Oven",
"Made in the 1 8 5 0 ' s . this coal-powered unit quickly blackens any"
+ "favorite dish.",
865.78,
"each"),
294 Shopping Bag: un carro de la cornpra en JavaScript
15.43,
"each") ,
new product ( "Toaster",
"BBQ-style toaster. Only a moderate shock hazard.",
25.78,
"each"),
new product ("Washer",
"Does a great job on partially everything.",
345.61,
"each")
);
...
... etc ...
...
categoryset = new Array(
new category( '"Appliances","Kitchen machines to make life easier"),
new category("Buildings", "Architectural structures your can't " +
"resist"),
new category("Clothing", "Fashionably questionable apparel for +
"the 21st century"),
new category("E1ectronics", "Nifty gizmos that drain your wallet"),
new category("Food", "The best product to order over the Net"),
new category( "Hardware", "All kinds of general purpose +
"construction tools") ,
new category("Music", "The hottest new instruments from places +
"you've never heard of")
);
1
"resist"),
new category ( '"Clothing","Fashionably questionable apparel for + 'I
"construction tools" ) ,
new category( "Music", "The hottest new instruments from places 'I +
"you've never heard of")
);
El valor de la variable categorySet sera un array. Cada uno de 10s elementos del
array sera un objeto category construido a partir de dos argumentos, un nom-
bre y una descripcion. Al primer argument0 se le asigna el nombre de la propie-
dad y a1 segundo su descripcidn. Vamos a revisar de nuevo el contenido de la
linea 14 del constructor de categorias:
this.prodLine = eval(name);
El valor deprodline sera eval (name). Asi pues, la llamada a category ( ) que
tiene lugar en la linea 249 implica queprodLineequivale a eval ( "Appliances ) , 'I
es decir, a Appliances. Ahora, la categoria Appliances lo sabe todo sobre sus pro-
ductos (esta informacion se encuentra dentro del array prodline). Cada uno de
10s elementos de categorySet representa otra categoria de Shopping Bag. Es decir,
que la inclusion y eliminacidn de categorias es realmente sencilla.
function Bag() {
this.taxRate = .06;
this.taxTota1 = 0;
this.shipRate = .02;
this.shipTota1 = 0;
this.subTota1 = 0;
this.bagTota1 = 0;
this.things = new Array ( ) ;
1
shoppingBag = new Bag();
Hay dos variables con valores arbitrarios: taxRate y shipRate. Una es un multiplo
de 10s impuestos estatales. La otra se utiliza para calcular 10s precios del transpor-
te. Quiza la estructura de impuestos con la que debamos trabajar no se parezca
296 Shotming Bag: un carro de la comma e n IavaScriDt
en nada a Csta. Aun hay otras tres variables, taxTota1, subTotal y shipTotaZ, que
son la suma de 10s impuestos de todos 10s productos, la suma del importe total
que ha de pagar el usuario y 10s portes. La ultima variable es un array. things
contendra todos 10s productos y la cantidad de ellos que seleccionara el usuario.
A la variable ShoppingBag se le asigna el valor de Bag ( 1 . Vamos de compras.
I
I
I
I
I
I
I I
I
I
I
I
I
I
Categoria j
siguiente
I
I
manager.html
Toda esta funcionalidad la tenemos en el archivo rnanager.htrnZ.
43 1
44 infoStr = header + intro + storeStr + footer;
45 parent.frames[O].location.replace('javascript:
46 parent.frames[ll.infoStr');
47 I
48
49 function portal ( ) {
50 gimmeControl = false;
51 parent.frames[O].location.href = "search/index.html";
52 1
53 function display(cOffset, p0ffset) {
54 if(!browseControl) {
55 alert("Start shopping by selecting a product category from
56 + "Show All Categories or searching products from Product
Search. ) ;
'I
57 return;
58 I
59 gimmeControl = true;
60 if (curPLoc + poffset < 0 I I curPLoc + poffset ==
61 categorySet[curCLocl.prodLine.length) {
62 if (curPLoc + pOffset < 0 ) I
63 if (curCLoc - 1 < 0) { curCLoc = categorySet.length - 1; 1
64 else { curCLoc--; 1
65 curPLoc = categorySet[curCLocl.prodLine.length - 1;
66 1
67 else if (curPLoc + pOffset ==
categorySet[curCLoc].prodLine.length) {
68 if (curCLoc + 1 == categorySet.length) { curCLoc = 0; 1
69 else { curCLoc++; 1
70 curPLoc = 0;
71 1
72 1
73 else {
74 if (curCLoc + coffset < 0 I I curCLoc + coffset ==
75 categorySet.length) {
76 curCLoc = (curCLoc + coffset < 0 ? categorySet.length - 1 :
0) ;
77 1
78 else { curCLoc += c0ffset; 1
79 if (coffset == -1 1 1 coffset == 1) { curPLoc = 0; }
80 else if (pOffset == 0 ) {
81 curPLoc = (curPLoc >= categorySet[curCLoc].prodLine.length
? O :
82 curPLoc)
83 1
84 else { curPLoc = curPLoc + pOffset; 1
85 1
86 infoStr = '<HTML><HEAD><TITLE>ProductName</TITLE></HEAD>' +
87 '<BODY><TABLECELLPADDING=3><TR><TDVALIGN=TOP COLSPAN=2>' +
88 '<FONT FACE=Tahoma><H2>Shopping Bag: <I>' +
89 categorySet[curCLocl.name + '</I></H2><TR>'+
300 Shopping Bag: un carro de la compra en JavaScript
138 return;
139 1
140 gimmeContro1 = false;
141 var header = '<HTML><HEAD><TITLE>YourShopping Bag</TITLE>'+
142 '</HEAD><BODYBGCOLOR=FFFFFF +
143 'onLoad="parent.frames[ll.runningTab(document.forms[Ol);"~';
144 var intro = '<H2>YourShopping Bag!! !</H2>'+
145 '<FORM onReset="' +
146 'setT~meout(\'parent.frames[ll.runningTab(document.forms[Ol)
147 \ ' , ' + '25);">';
148 var tableTop = '<TABLEBORDER=l CELLSPACING=O CELLPADDING=5>'+
149 '<TR><TH><B>Index' +
150 '<TH><B>Product<TH><B>Category'+
151 '<TH><B>PLU<TH><B>Unit Price' +
152 '<TH><B>Quantity<TH><B>ProductTotal' +
153 '<TH><B>Remove'+
154 ' </TR>' ;
155 var itemStr = " ;
156 for (var i = 0; i < shoppingBag.things.1ength; i++) {
157 itemStr += '<TR>' +
158 '<TDALIGN=CENTER>' + (i + 1) + '</TD>' +
159 '<TD>'+ shoppingBag.things[il.name + '</TD>'+
160 '<TD>'+ shoppingBag.things[i].category + '</TD>'+
161 '<TD>'+ shoppingBag.things[il.plu + '</TD>'+
162 '<TD ALIGN=RIGHT>$' +
163 parent.frames[1l.numberFormat(shoppingBag.things[il
164 .price) + '</TD>'+
165 '<TD ALIGN=CENTER>' +
166 parent.frames[ll.genSelect(shoppingBag.things[il.price,
167 shoppingBag.things[il.itemQty, i) + '</TD>'+
168 '<TD ALIGN=CENTER><INPUT TYPE=TEXT SIZE=10 VALUE="' +
169 parent.frames[ll.numberFormat(shoppingBag.things[il.price *
170 shoppingBag.things[i].itemQty) +
171 "' onFocus="this.blur() ;"></TD>'+
172 '<TDALIGN=CENTER><INPUT TYPE=CHECKBOX></TD>'+
173 '</TR>';
174 1
175 var tableBottom = '<TR>'+
176 Y T D ALIGN=RIGHT COLSPAN=b>SubTotal:</TD>' +
177 '<TDALIGN=CENTER><INPUTTYPE=TEXT SIZE=10 NAME="subtotal" ' +
178 onFocus="this.blur(); "></TD></TR>'+
179 '<TR><TDALIGN=RIGHT COLSPAN=6> + 6% Tax:</TD>' +
180 '<TD ALIGN=CENTER><INPUT TYPE=TEXT SIZE=10 NAME="tax" ' +
181 'onFocus="this.blur();"></TD></TR><TR><TD ALIGN=RIGHT
COLSPAN=6> +
182 '2% Shipping:</TD><TDALIGN=CENTER><INPUT TYPE=TEXT +
183 'SIZE=10NAME="ship"onFocus="this.blur() ; "></TD></TR>'+
184 ' <TR>' +
185 '<TDALIGN=RIGHT COLSPAN=3><INPUTTYPE=BUTTON VALUE="Check
Out" +
186 'onClick="parent.frames[ll.checkOut(this.form);"></TD>'+
302 Shopping Bag: un carro de la compra en JavaScript
269 return;
270 1
271 if(shoppingBag.things.1ength == 0 ) {
272 showstore( ) ;
213 return;
274 1
275 var header = '<HTML><TITLE>ShoppingBag Check Out</TITLE>' +
276 '<BODY BGCOLOR=FFFFFF>':
277
278 var intro = '<H2>ShoppingBag Check Out</H2><FORM METHOD=POST '
279 + 'ACTION="http://your.webserver.com/cgi-bin/bag.cqi~'+
304 Shopping Bag: un carro de la compra en JavaScript
280 'onSubmit="returnparent.frames[ll.cheapCheck(this);">';
281
282 var shipInfo = '<TABLE BORDER=O CELLSPACING=O CELLPADDING=5>' +
283 '<TR><TD><B>ShippingInformation</TD></TR>'+
284 '<TR><TD>FirstName</TD><TD><INPUT TYPE=TEXT NAME="fname">
</TD>' +
285 '</TRxTRXTD>LastName</TD><TD>' +
286 '<INPUT TYPE=TEXT NAME="lname"></TD></TR><TR><TD>Company
Name</TD>' +
287 '<TD><INPUT TYPE=TEXT NAME="cname">.c/TD></TR><TR>' +
288 '<TD>StreetAddressl</TD><TD><INPUTTYPE=TEXT
NAME= " saddressl > * +
'I
CHECKED> ' +
302 ' ' +
303 ' Amex <INPUT TYPE=RADIO NAME= "ctype" VALUE= "amex"> ' +
304 ' ' +
305 'Discover <INPUT TYPE=RADIO NAME="ctype" VALUE="disc"> ' +
306 ' </TD></TR>'+
307 '<TR><TD>CreditCard Number</TD>' +
308 '<TD><INPUTTYPE=TEXT NAME="cnumb"></TD></TR><TR>' +
309 '<TD>ExpirationDate</TD><TD><INPUTTYPE=TEXT NAME="edate">
</TD>' +
310 'C/TR><TR><TD><INPUTTYPE=SUBMIT VALUE="Send Order"></TD>'+
311 '<TD><INPUT TYPE=RESET VALUE="Clear Info"></TD></TR>'+
312 '</TABLE>';
313
314 var itemInfo = " ;
315 for (var i = 0; i < shoppingBag.things.1ength; i++) {
316 itemInfo += '<INPUT TYPE=HIDDEN NAME="prod' + i +
317 "' VALUE="' + shoppingBag.things[il .plu + + I - '
Una nota rapida. iSe ha fijado que todo el c6digo de JavaScript se encuentra
dentro de una etiqueta BODY? Como a1 principio se cargan las imagenes y se
crean 10s objetos, Netscape Navigator mostrara un fondo gris en la ventana (En
este caso, en el marco) hasta que se complete todo el proceso. El explorador ana-
lizara el contenido de la etiqueta BODY y se encontrara con el atributo BGCOLOR.
Asi corregira el color antes de proceder con el resto del trabajo que tiene que
realizar.
Variables
A continuacion tenemos el codigo que hace que se muestren 10s productos en
la pantalla. E n las lineas 15-18 se configuran cuatro variables, y en las lineas
53-103 se define la funcion display ( ) . L a variable girnrneControZ le indica a la
aplicacion si hay algo en la pantalla (un producto) que se pueda agregar a la bol-
sa de la compra. La variable browsecontrol se encarga de que se cumpla la regla
que dice que el usuario ha de empezar la compra haciendo clic sobre el vinculo
"Show All Categories" o sobre "Product Search" (regla 1 ) . Vamos a ver estas dos
Shopping Bag: un carro de la cornpra en JavaScript 307
1
infoStr = '<HTML><HEAD><TITLE>ProductName</TITLE></HEAD>'+
'<BODY><TABLE CELLPADDING=3><TR><TD VALIGN=TOP COLSPAN=2>' +
'<FONT FACE=Tahoma><H2>Shopping Bag: < I > ' +
categorySet[curCLocl.name + ' < / I > < / H 2 > < T R >+'
' < T D VALIGN=TOP><IMG SRC="' +
categorySet[curCLocl .prodLine[curPLocl.icon.src +
' " > < / T D > < T DVALIGN=TOP><FONT FACE=Tahoma>' +
'<B>Name: < / B > ' + categorySet[curCLoc].prodLine[curPLoc].name +
'<BR><B>Description:< / B > ' +
categorySet[curCLocl.prodLine[curPLoc].description + ' < B R > '+
'<B>Price: < / B > $ ' +
numberFormat~categorySet~curCLocl.prodLine[curPLocl.price)+ ' / ' +
categorySet[curCLoc].prodLine[curPLoc].unit + ' < B R > ' +
'<B>PLU: < / B > ' + categorySet[curCLoc].prodLine[curPLocl.plu +
'c/TD></TR></TABLE></BODY>~/HTM~>';
parent.frames[O].location.href =
'javascript:parent.frames[ll.infoStr';
1
display( )
La funcion display ( ) ha de desarrollar tres acciones:
Determinar si puede mostrar un producto.
Determinar la categoria/producto que quiere ver el usuario.
Mostrar el producto.
<TD>
<A HREF="javascript: display(-1,O); ">Previous Category<A>
Shopping Bag: un carro de la compra en JavaScript 309
</TD>
<TD>
<A HREF="javascript: display( 0, -1) ; ">Previous Product<A>
</TD>
<TD>
< A HREF="javascript: display(0,l); " > N e x t Product<A>
</TD>
<TD>
< A HREF="javascript : display ( 1 , O ); " > N e x t Category<A>
</TD>
Excepciones a la regla
Tiene sentido. Si queremos retroceder una categoria, restamos 1 a1 numero de
la categoria en la que nos encontramos. Si queremos ver la siguiente categoria,
entonces sumaremos 1. Per0 existen tres excepciones a esta regla que requieren
cierta explicacih:
Construccion de la pagina
Una vez que la aplicacion conoce el numero de la categoria y del producto,
puede proceder a crear el c6digo HTML de la pagina en la que se mostrara el
producto. Casi todo el codigo restante de la funcion display[) se ha dedicado a
mostrar el producto en la pantalla. Vamos a ver las lineas 86-102:
Como se puede ver, todo se basa en una gran concatenacion de codigo HTML
para hacerse con el valor de la variable infoStr. Vea que 10s valores de curPLoc y
curCLoc son de vital importancia para establecer la referencia con la informacion
del producto. categoryset [curCLocI es la encargada de referirse a la catego-
ria correcta, mientras categoryset[curCLocI .prodLine [curPLocI se refie-
re a1 producto correcto. Una vez que se han determinado 10s valores de curCLoc
y curPLoc, podremos mostrar la informacibn del producto deseado.
DespuCs de que infoStr tenga todo el codigo HTML que necesita para mostrar el
producto, la propiedad href que se encuentra en el marco superior de trabajo
mostrara este valor. Para ello se utiliza el protocolo javascript : . No olvide-
mos que debido a1 alcance de este protocolo, tendremos que establecerle una
referencia absoluta (por ejemplo, parent.frames [ 1 ] .infostr en vez de infoStr).
Esta tecnica se ha visto en el segundo capitulo de este libro.
function showStore0 (
gimmeContro1 = false;
var header = '<HTML><TITLE>Category</TITLE><BODYBGCOLOR=FFFFFF>';
var intro = '<H2>Shopping Bag Product Categories</H2><B>';
var footer = '</DL></BLOCKQUOTE></BODY></H~~L>~;
var storeStr = '<BLOCKQUOTE><DL>';
for (var i = 0; i < categorySet.length; i++) (
storeStr += '<DT><A HREF="javascript: parent.frames [ 11 .recall( ' + i
+ ' , O);">' + categorySet[i].name + '</A><DD>'+
categorySet[i].description + '<BR><BR>';
1
infoStr = header + intro + storeStr + footer;
parent.frames[O].location.replace('javascript:
parent.frames[ll.infoStr');
1
Shopping Bag: un carro de la compra en JavaScript 313
function gimmeone ( ) {
if (!gimmeControl) {
alert ("Nothing on this screen to give you. " ) ;
return;
>
for (var i = 0; i < shoppingBag.things.length; i++) {
if (categorySet[curCLocl.prodLine[curPLocl.plu==
shoppingBag.things[i].plu) {
alert("That's already in your bag. You can change the quantity +
"by choosing View/Change Bag. ;
I")
return;
1
1
shoppingBag.things[shoppingBag.things.lengthl =
categorySet[curCLocl.prodLine[curPLocl;
shoppingBag.things[shoppingBag.things.length - 11.itemQty = 1;
shoppingBag.things[shoppingBag.things.length - 11.category =
categorySet[curCLoc].name;
alert("0K. You put the " +
shoppingBag.things[shoppingBag.things.length - 11.name +
" in your bag. " ) ;
1
Shopping Bag: un carro de la compra en JavaScript 31 5
function allowAny(t) [
var findings = new Array();
for (var i = 0 ; i < prodProfiles.1ength; i + + ) {
var compareElement = ref.categorySet[prodProfiles[il [Oll.
p r o d L i n e [ p r o d P r o f i l e s [ i l [ l ] I .name + ' ' +
ref.categorySet[prodProfiles[il [Oll.prodLine[prodProfiles[i1[111.
description + ' +
ref.categorySet[prodProfiles[i][Oll.prodLine[prodProfiles[il~lll.
price.toString0 + ' ' +
ref.categorySet[prodProfiles[il[Oll.prodLine[prodProfiles[il~lll.
plu;
compareElement = compareElement.toUpperCase0;
for (var j = 0; j i t.length; j + + ) {
var comparestring = t[jl.toUpperCaseO;
if (compareElement.indexOf(compareString) ! = -1) {
findings[findings.lengthl = new Array(prodProfiles[il L O ] ,
Shopping Bag: un carro de la compra en JavaScript 319
Cada resultado mostrara el nombre, descripcion, precio y numero PLU del pro-
ducto. Esta funci6n se repite con todos 10s elementos de results y utiliza 10s en-
teros results [ i ] [ 0 ] y results [ i ] [ 1] con objeto de acceder a la informacion
de prodline. En otras palabras, si el resultado tiene el siguiente aspecto:
Posiblemente no le sorprenda saber que hay una serie de funciones listas para
adaptarse a las necesidades de Shopping Bag. Son las siguientes:
showBag ( ) . Muestra el contenido de la bolsa de la compra.
genselect ( 1 . Genera listas de seleccion dinhmicas para cambiar la can-
tidad de productos.
runningTab ( ) . Efectua 10s calculos correspondientes y muestra 10s pre-
cios de 10s productos.
numberFormat ( ) . Se asegura de haber utilizado el formato correct0 en las
operaciones matematicas
round ( ) . Ajusta 10s calculos.
changeBag ( ) .Elimina las selecciones de 10s productos y cambia el numero
de estos que tenga el usuario en su bolsa de la compra.
function showBag ( ) {
if (shoppingBag.things.1ength == 0 ) I
Shopping Bag: un carro de la compra en JavaScript 323
var itemstr = I n ;
'onClick="parent.frames[l].checkOut(this.form):"~</TD>'+
'<TD ALIGN=RIGHT><INPUT TYPE=RESET VALUE="Reset Qtys"></TD>'+
'<TD ALIGN=RIGHT><INPUT TYPE=BUTTON VALUE="Change Bag" +
'onClick="parent.frames[l].changeBag(this.form,true):"></TD>'+
'<TD ALIGN=RIGHT>Total:</TD><TDALIGN=CENTER>' +
'<INPUT TYPE=TEXT NAME="total" SIZE=10 onFocus="this.blur(); " > ' +
'</TD></TR>'; ?u
Veremos que showBag ( ) no hace otra cosa que generar la tabla de la figura 8.8.
Pero, showBag ( tendra que comprobar antes de nada que la bolsa de la com-
pra contiene algo:
if (shoppingBag.things.length == 0) I
alert("Your bag is currently empty. Put some stuff in.");
return:
1
gimmecontrol = false;
var header = '<HTML><HEAD><TITLE>YourShopping Bag</TITLE>' +
'</HEAD><BODYBGCOLOR=FFFFFF ' +
'onLoad="parent.frames[ll .runningTab(document.forms[O]);">';
var itemStr = * I ;
Las etiquetas OPTION creadas son muy sencillas. A su atributo VALUE se le asig-
nara el precio por unidad del producto multiplicado por i, que es la cantidad
asociada con esta opcion. Por ejemplo, u n producto que cueste $1.OO la unidad,
generara las siguientes etiquetas OPTION:
parent.frames[l].genSelect(shoppingBag.things[il.price,
shoppingBag.things[i].itemQty, i )
Se puede observar que el valor de idx siempre coincidira con el de i, que se ini-
cia en la linea 156 y se incrementa de uno en uno. Si el usuario tiene 10 produc-
tos en la bolsa de la compra, el rango de idx sera 1-10. Por lo tanto, las etiquetas
de seleccion que creara the showBag ( ) ser5n asi:
function runningTab(form0bj) {
var subTotal = 0;
for (var i = 0; i < shoppingBag.things.1ength; i++) {
subTotal += parseFloat(formObj.elements[(i * 3 ) + 11.value);
1
form0bj.subtotal.value = numberFormat(subTota1);
formObj.tax.value = numberFormat(subTota1 * shoppingBag.taxRate);
form0bj.ship.value = numberFormat(subTota1 * shoppingBag.shipRate);
form0bj.total.value = numberFormat(subTota1 +
round(subTota1 * shoppingBag.taxRate) + round(subTota1 *
shoppingBag.shipRate)) ;
shoppingBag.subTota1 = form0bj.subtotal.value;
shoppingBag.taxTota1 = form0bj.tax.value;
shoppingBag.shipTota1 = form0bj.ship.value;
shoppingBag.bagTota1 = formObj.total.value;
1
function numberFormat(amount) {
var rawNumStr = round(amount) + " ;
rawNumStr = (rawNumStr.charAt(0)== ' . ' ? ' 0 ' + rawNumStr :
rawNumStr);
if (rawNumStr.charAt(rawNumStr.1ength - 3 ) == ' . ' ) {
return rawNumStr
}
else if (rawNumStr.charAt(rawNumStr.1ength - 2 ) == ' . ' ) {
return rawNumStr + ' 0 ' ;
1
else { return rawNumStr + ' . G O ' ; 1
}
function round(number,decPlace) {
decplace = (!decPlace ? 2 : decPlace);
return Math.round(number *
Math.pow(lO,decPlace)) / Math.pow(lO,decPlace);
}
http://help.netscape.com/kb/client/970930-1.html
h ttp://www.psc.edu/general/software/packages/ieee/ieee.html
A1 revisar este codigo HTML vemos que inicialmente, 10s campos donde se
mostrara el total estan vacios. La llamada a la funcion runningTab ( ) en el con-
trolador de eventos onLoad de este documento se encargar6 de publicar 10s valo-
res de dichos campos. Cada uno de 10s campos tiene el siguiente c6digo:
onFocus='this.blurO;'
"Check Out"
Cuando el usuario ya ha terminado de comprar, tendra que introducir la in-
formation necesaria para efectuar el pago y confirmar el pedido. Al hacer clic en
este boton, la aplicaci6n llama a la funcion checkout ( ) que se encarga de ha-
cer dos cosas:
Esta funcion es larga, asi que la dividiremos en dos partes. Aqui tenemos el
contenido de las lineas 263-312:
function checkOut(form0bj) {
gimrneContro1 = false;
if(!confirm("Do you have every product in the right quantity + 'I
"you need? Remember that you have to choose Change Bag to remove + 'I
'<TR><TD><B>Shipping Informationc/TD></TR><TR>'+
'<TD>FirstName</TD>iTD><INPUTTYPE=TEXT NAME="fname"></TD></TR>' +
'<TR><TD>LastName</TD><TD><INPUTTYPE=TEXT NAME="lname">'+
'</TD></TR><TR><TD>Company Name</TD>' +
'<TD><INPUTTYPE=TEXT NAME="cname"></TD>i/TR><TR>' +
'<TD>StreetAddreSsl</TD><TD><INPUTTYPE=TEXT NAME="saddressl">'+
'</TD></TR><TR><TD>Street Address2</TD><TD>'+
'<INPUTTYPE=TEXT NAME="saddress2"></TD></TR><TR>' +
'<TD>City</TD><TD><INPUT TYPE=TEXT NAME="city"></TD></TR>'+
'<TR><TD>State/Province</TD><TD><INPUT TYPE=TEXT NAME="stpro">'+
'</TD></TR><TR><TD>Country</TD><TD>' +
'<INPUT TYPE=TEXT NAME="country"></TD></TR><TR>' +
'<TD>Zip/MailCode</TD><TD><INPUTTYPE=TEXT NAME="zip"></TD>'+
'</TR><TR>ITD><BR><BR></TD></TR~</TA~LE>';
Es muy larga, per0 completamente estatica. El codigo que tenemos aqui se en-
carga de generar el formulario de la figura 8.8. El formulario contiene una serie
de campos con objeto de que el usuario introduzca la informacion solicitada. El
nombre de cada uno de estos campos es unico para que el script del lado del ser-
vidor pueda identificar toda la informacion que recibe.
La ultima parte de la funcion checkout ( ) prepara 10s campos HIDDEN para que
registre todos 10s productos que haya seleccionado el usuario. Aqui tenemos el
contenido de las lineas 3 14-319:
De esta forma se genera un campo HIDDEN cuyo nombre sera prod + el valor
de i. El valor se ajustara a la sintaxis de la cantidad determinada por PLU. Asi,
si el usuario pide dos bolsas de patatas fritas, el valor de este campo HIDDEN se-
ria VALUE= '' FRI1- 2 " . DespuCs de crear un campo HIDDEN para cada uno de 10s
Shopping Bag: u n carro de la cornpra en JavaScript 333
Se afiade un boton "Send Order" para enviar la informacion y otro Tlear Info"
para borrar el contenido del formulario. Antes de seguir, conviene observar que
el controlador de eventos onsubmit es el que se encarga de llamar sobre la mar-
cha a cheapcheck( ) . Esta funcion se limita a asegurarse que, cuando se envia
el formulario, no queda ningun campo vacio.
Este es el contenido de las lineas 337-352:
function cheapCheck(form0bj) {
for (var i = 0; i < formObj.length; i++) {
if (formObj[i].type == "text" && formObj.elements[il.value == " ' I ) {
alert ( "You must complete all fields. " ) ;
return false;
>
I
if(!confirm("If all your information is correct, choose OK to send " +
"your order, or choose Cancel to make changes.")) {
return false;
1
alert("Thankyou. We'll be living off your hard-earned money soon.");
shoppingBag = new Bag();
showstore( 1 ;
return true;
I
Completar la pantalla
Una vez que la funcion showBag ( ) header, intro, tableTop, itemStr, totallnfo,
tabZeBottom yfooter ha cambiado 10s valores que se necesitaran para crear una
pantalla con sentido, la funcion colocara toda esta informacion en la pantalla.
Veamos el contenido de las lineas 195-197:
"ResetQtys"
Este boton se limita a borrar 10s cambios que se han efectuado en el formula-
rio. Per0 si se selecciona "Change Bag", podremos guardar permanentemente 10s
cambios efectuados en la bolsa de la compra.
Shopping Bag: un carro de la compra en JavaScript 335
"Change Bag"
Supongamos que el usuario ha efectuado una serie de cambios en la cantidad
de productos y que ha seleccionado la casilla de verificacion "Remove"de un par
de productos. Al seleccionar "Change Bag" la aplicacion guarda estos registros y
vuelve a mostrar la bolsa de la compra, per0 reflejando ahora 10s nuevos conte-
nidos y cantidades de la bolsa de la compra. Esta es la funcion changeBag ( )
que se encuentra en las lineas 246-261 :
function portal0 I
gimmeContro1 = false;
parent.frames[O].location.href = "search/index.html";
I
function h e l p 0 {
gimmeContro1 = false;
parent.frames[Ol.location.href = "intro.htm1";
I
function freshstart0 {
if (parent.frames[O].location.href != "intro.htm1") { help(); }
1
Posibles ampliaciones
Tambien podemos aplicar un poco de creatividad. Estas son algunas de ellas:
</SELECT>
Aunque se trata de codigo puro y duro, podremos utilizar una logica similar a
la utilizada en g e n s e l e c t ( ) para obtener un resultado mas dinamico. Cuando
se completa la busqueda, podremos buscar 10s productos cuya categoria haya
seleccionado el usuario, por lo tanto, estaremos refinando la busqueda.
Otra de las propiedades que podemos agregar es la capacidad de localizar pro-
ductos a partir de un rango de precios. Si un comprador busca productos con
precios inferiores a $50, mayores de $100 o entre ambas cantidades, podremos
trabajar con etiquetas > , < , >= y <=. Tendremos que modificar las funciones
v a l i d a t e ( ) y f o r m a t R e s u l t s ( ) para lograrlo.
lncluir cookies
Supongamos que nuestro sitio Web tiene productos que cambian con cierta
velocidad. Quiza, de esta forma 10s compradores nos visiten con mas frecuen-
cia. Seria conveniente hacer que no tuviesen que rellenar la informacion del pago
cada vez que quieran adquirir un producto. iPor qut no incluir las cookies que
se vieron en el capitulo 7? De esta forma, la informacion del usuario se guarda-
ria en su propio explorador, de tal manera que se podria utilizar para rellenar
automaticamente el formulario de pago de este usuario. Esta funcionalidad pue-
de ser algo desafiante, per0 cuando la complete seguro que se siente como una
especie de htroe de JavaScript. Con las funcionesGetCookie ( ) y S e t c o o k i e ( )
podremos escribir y extraer informacion de las cookies. Tambitn necesitaremos
una funcion que se encargue de extraer la informaci6n correspondiente a cada
uno de 10s campos del formulario y otra que la publique.
Capitulo 9
Cifrado e n JavaScript
IVigenere Q p h e r d
que han poblado la historia de la humanidad. Otros sistemas no tienen mas que
unas semanas de antigiiedad y proceden de las mentes inquietas de jovenes
adolescentes que llegan a ellas en momentos de euforia despues de batir el record
de su video juego favorito. Independientemente de cual sea la procedencia del sis-
tema, todos ellos se pueden clasificar en tres grupos: ocultacion, transposicion
y sustitucion.
Los sistemas de cifrado de ocultacion incluyen texto plano dentro del texto
cifrado. El destinatario sera quien ha de conocer que letras o simbolos ha de eli-
minar del texto cifrado para hacerse con el mensaje. Por ejemplo, aqui tenemos
u n texto cifrado:
Si quitamos todos 10s numeros, nos encontraremos con la frase "me gusta el
chocolate". Y ique hay de esta otra frase?
La primera letra de cada palabra revela el mensaje: Vete ya. Es cierto que ambos
sistemas son muy sencillos, pero hay gente que tiene mucha mas imaginacion a
la hora de ocultar mensajes. Por cierto, este sistema de ocultacion no necesita
texto cifrado, con 10s ejemplos que hemos visto anteriormente. Supongamos que
tenemos un bote de tinta invisible, como la que se utiliza en 10s articulos de bro-
ma. Con ella podemos enviar mensajes de texto. Per0 en un caso mas extremo,
encontramos a un hombre llamado Histiaeus, que vivi6 en el siglo V a.C., el cual
rap6 la cabeza de un esclavo de su confianza y tatuo un mensaje en su cabeza.
Cuando a1 esclavo le volvio a crecer el pelo, Histiaeus lo envio a encontrarse con
Aristagoros, quien volvio a rapar la caheza del esclavo para leer el mensaje que
le incitaba a la revolucion.
La encriptacion por transposicion tarnbien conserva 10s caracteres del texto
plano dentro del texto cifrado. Para encriptar el texto basta con cambiar la po-
sicion de 10s caracteres. Por ejemplo, mire esta frase:
le er aq cu efi ta um sp oe ta e
8-16-12-1 1 21-16-4-16-20
344 Cifrado en JavaScript
Piratear el codigo
El texto cifrado que genera esta aplicacion puede parecer complejo a primera
vista. En realidad, cualquier experto en cifrado lo podra piratear en cuestion de
minutos con un lapiz y un papel como etnicas armas. Afortunadamente, las
medidas de seguridad de la actualidad utilizan algoritmos mucho mas seguros
como RSA, IDEA y el triple DES. No puedo ensefiar c6mo se rompen estos siste-
mas, pero dare una pista a traves de la cual se puede ver la vulnerabilidad de 10s
sistemas de cifrado por transposicion.
El arma principal que se usa contra estos es la distribucion basada en la frecuen-
cia de letras. Es decir, en cualquier conversacion hay unas letras que aparecen
mas que otras. Las letras mas comunes son E-T-N-R-0-A-I-S y las menos co-
munes J, K, Q X y Z.
Otra forma de comprometer un sistema de cifrado sencillo es analizando las
cadenas de dos y tres caracteres (digraphs y trigraphs, respectivamente). Estos
elementos tambikn se repiten con cierta frecuencia en las conversaciones coti-
dianas. Por ejemplo, el ejkrcito de 10s EE.UU. considera que 10s siguientes elemen-
tos son 10s que mas se repiten en su idioma: en, er, re, nt, th, on, in, ent, ion, and,
ing, ive, tho yfor. Los menos frecuentes son: df, hu, ia, It, rnp, eri, hir, iet, der y dre.
Las letras mas frecuentes no solo indican cuales pueden ser el resto de letras de
la palabra, sino que tambien dan pistas sobre las letras que se encuentran en las
palabras colindantes. Pensemos por u n momento la cantidad de estos elementos
que usamos a diario: es, si, no, yo, tu, el, la ... Y la lista sigue. Aunque 10s siste-
mas de cifrado que utilizamos en esta aplicacion no son 10s mas seguros, si re-
sulta divertido trabajar con ellos. Y seguro que en ocasiones evitara que algun
intruso lea nuestros mensajes.
Caesar
Este sistema tiene este nombre porque es el que utilizaba Julio Cksar para co-
municarse con 10s generales de sus ejercitos. Es uno de 10s primeros sistemas de
cifrado utilizados para encriptar mensajes. El algoritmo usado es bastante sim-
ple. Se limita a mover las letras del alfabeto entre 1 y 25 lugares (de la b a la z).
De esta forma, si se trabaja con un nivel 3 , la letra a del texto plano se conver-
tira en la d, y viceversa. Las letras que sobrepasen la posicih de la z, seguiran
Cifrado en IavaScriDt 345
contando desde el principio. Es decir, que con un nivel 3 , la z del texto plano
pasara a ser la c del texto cifrado. El numero es la llave que ha de poseer el des-
tinatario y el remitente del mensaje.
Observese que, una vez que se ha seleccionado una llave, todos 10s caracteres
del texto plano estaran relacionados con el mismo caracter del texto cifrado. Por
ejemplo, u n nivel 3 indica que la a siempre se convertira en la d. Es decir, que
tecnicamente habra un alfabeto cifrado. Por eso se dice que este sistema es mono-
alfabetico.
Vigenere
Este sistema lo ideo el matematico Blaise de Vigenere en el siglo XVI. Se trata de
un sistema de cifrado poli-alfabetico porque utiliza mas de un alfabeto cifrado.
Es decir, la letra a del texto plano no se correspondera siempre con la letra d del
texto cifrado.
En vez de numeros, este sistema de encriptacion utiliza una palabra. Suponga-
mos que queremos cifrar el texto meet a t midnight y que seleccionamos como
llave la palabra vinegar. Las letras de la llave se alinean en sucesion con las letras
del texto plano:
vine ga rvinegar
meet at midnight
Bien. La V es la letra numero 22a del alfabeto. La I es la 9a . Las letras n, e, g, a
y r son las 14a, 5a, 7a, 1” y lSa, respectivamente. Asi que la letra m del texto
plano se movera 22 posiciones, la primera e se desplazara 9 y la segunda 14, etc.
De esta forma obtendremos:
hmrx gt ddlammhk
Si nos fijamos bien, este sistema de cifrado es igual que Caesar, con la diferen-
cia de que se aplica sobre la marcha. En cada caracter se aplica un nuevo sistema
Caesar.
Analisis de la sintaxis
Afortunadamente, esta aplicacion tecnicamente necesita dos archivos. Mejor
aun, solo nos fijaremos en el codigo de uno de ellos. Estos archivos sonindexhtml
y dhtrnl.js (dhtrnZ.js se vio en el capitulo 6). Antes de iniciar el analisis del codi-
go, merece la pena que nos detengamos a considerar el aspect0 que presentara
la aplicacion. Su construccion se har6 desde un punto de vista muy basico. En el
carro de la compra, el cual hemos tratado en el capitulo anterior, ya vimos otra
aplicacion que utilizaba la orientacion de objetos, per0 ahora iremos u n poco mas
alla.
Esta aplicacion cuenta con dos sistemas de cifrado. Cada uno de ellos tiene una
serie de elementos en comun con el otro, independientemente del tip0 de en-
criptacion que aplique. No olvidemos que hay tres tipos de sistemas de cifrado:
ocultacion, trasposicion y sustitucion. Aqui veremos dos sistemas de sustitu-
ci6n: Caesar y Vigenere. La figura 9.5 nos muestra la estructura que acabamos
de describir.
Como podemos ver, el numero de tipos y sistemas de cifrado que se puede aiia-
dir a la estructura sin modificar nada es enorme. Tambitn podemos tener "sub-
clases" de una subclase. De nuevo nos podemos aprovechar del diseiio orientado
a objetos. No lo olvidemos mientras analicemos el cddigo de las siguientes pagi-
nas. Veremos la facilidad con la que se puede agregar mas sistemas de cifrado a
la aplicacidn sin tener que modificar nada.
En el ejemplo 9.1 podemos ver el contenido del archivo indexhtrnl.
1 <HTML>
2 <HEAD>
3 <TITLE>Cipher</TITLE>
4 <STYLE TYPE= " text / cs s " >
5 <!--
348 Cifrado en JavaScript
11 <SCRIPT LANGUAGE="JavaScriptl.2">
12 <!--
13
14 var caesar = '<FONT SIZE=2>Made famous by Julius Caesar, this
cipher * +
15 'performs character shifting (substitution). Plaintext is ' +
16 'enciphered by shifting forward each character of the alphabet
a ' +
17 'fixed number of characters.<BR><BR>Forexample, shifting by 1
I +
137
138
139 //-->
140 </SCRIPT>
141 < /HEAD>
142 <BODY BGCOLOR=#FFFFFF>
141
144 <DIV>
145 <TABLE BORDER=O>
146 <TR>
147 <TD ALIGN=CENTER COLSPAN=3>
148 <IMG SRC= images/cipher.jpg " >
I'
149 </TD>
150 </TR>
151 <TR>
152 <TD VALIGN=TOP WIDTH=350>
153 <FORM>
154 <SELECT NAME="Ciphers"
155 onChange="showCipher(this.options[this.selectedIndexl
.value); " >
156 <OPTION VALUE="caesar">CaesarCipher
157 <OPTION VALUE="vigenere">Vigenere Cipher
158 </SELECT>
159 </TD>
160 <TD ALIGN=CENTER>
161 <TEXTAREA NAME= "Data" ROWS= 15 COLS=" 40 ''
WRAP= PHYSICAL '' >< / TEXTAREA>
I'
162 <BR><BR>
163 <INPUT TYPE=BUTTON VALUE="Encipher"
164 onClick="routeCipher(this.form.Ciphers.selectedIndex,
165 this.form.Data.value, true);">
166 <INPUT TYPE=BUTTON VALUE="Decipher"
167 onClick="routeCipher(this.form.Ciphers.selectedIndex,
168 this.form.Data.value, false);">
169 <INPUT TYPE=BUTTON VALUE=" Reset "
170 onclick=" this.form . Data.value= ' ' ; " >
171 < /FORM>
172 </TD>
173 </TR>
174 < /TABLE>
175 < / DIV>
176
177 <SCRIPT LANGUAGE="JavaScriptl.2">
178 <!--
179 document.forms[O].Ciphers.selectedIndex = 0;
180 genLayer("caesar",50, 125, 350, 200, showName, caesar);
181 genLayer("vigenere",50, 125, 350, 200, hideName, vigenere);
182 //-->
183 </SCRIPT>
184 i/BODY>
185 </HTML>
352 Cifrado en JavaScript
genSelect('Shift', 35, 0 , 0 )
function C i p h e r 0 {
this.purify = purify:
this.chars = ~abcdefghijklmnopqrstuvwxyz0123456789';
1
nstructor Cipher ( ) ti
ene un mCtodo llamad
signaci6n de las propiedades es fAcil. Basta con asignar el valor que se
sea a una variable utilizando la sintaxis this.variable-name. La asig-
i6n de mCtodos es algo distinta. Lo primer0 que se ha de hacer es de-
r una funcion. Luego se utilizarA la sintaxis this.variable-name
a establecer una referencia que apunte a dicha funci6n. Esto es exada-
ente lo que ocurre en el constructor Cipher ( ) . El script contiene la
nci6n purify ( ) que acabamos de definir. cipher ( ) tiene una variable
amada this.purif y que hace referencia a1 mttodo purify. Obskrvese
que no hay parentesis. Asi se sabe que se trata de una referencia. Como el
valordethis.purifyespurify0,sepodriallamaralafunci6npurify() ,
on lo que se asignaria a this.purify el valor que se devolviese, fuese
cual fues
r, n .
No est6n mal. Por lo menos son sencillas. Todo lo que tenemos que hacer es
obligar a que se cuhplan. En las lineas 48-5 7 tenemos la funci6n purify ( ) :
function purify(rawText) {
if (!rawText) { return false; 1
var cleanText = rawText.toLowerCase0;
cleanText = cleanText.replace(/\s+/g,' I ) ;
cleanText = cleanText.repla~e(/[~a-zO-9\sI/g,");
if(cleanText.length == 0 1 1 cleanText.match(/"\s+$/) ! = null) {
return false;
I
return cleanText
I
354 Cifrado en JavaScript
cleanText = cleanText.replace(/\s+/g,' I ) ;
cleanText = cleanText.replace(/["a-z0-9\s]/g,");
I Esta expresion buscar5 todas las letras minusculas del abecedario, 10s digitos
Con objeto de saber quC caracteres tiene que valorar, Cipher utilizarfi la siguien-
te cadena:
this.chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
356 Cifrado en JavaScript
Se da por supuesto que todos 10s objetos Cipher conocen el formato de 10s datos
del usuario. Los sistemas de cifrado por sustitucion aun dan suponen mas cosas:
Cada uno tiene un nombre y una descripcion.
Cada uno utiliza un metodo general para sustituir 10s caracteres de las
cadenas de cifrado y descifrado.
Cada uno contiene informacion sobre el mCtodo general de sustitucion.
Esto es lo que diferencia un sistema de cifrado de otro.
Cada objeto Substitutioncipher tambien sera Cipher.
Asignar un nombre y una descripcion a 10s objetos es una tarea facil. Cualquie-
ra de las dos cadenas que se pasan durante la llamada a SubstitutionCipher ( )
sera completamente valida. Las variables caesar y vigenere que se iniciaron con
anterioridad con el c6digo HTML haran las funciones de descripciones. Asi nos
encargamos de la primera suposicion. iQue hay de la definition del metodo
general de sustitucion? Este mCtodo puede sustituir un caracter por otro. Cada
llamada a este metodo devolvera un caracter, que se sustituira por otro.
Sustitucion basica
Cada Substitutioncipher utiliza el mismo metodo para sustituir un caracter de
la cadena por otro. La funcion substitute ( ) que veremos a continuacion, se
definira como un mCtodo para cada ejemplo de Substitutioncipher:
else {
var shiftDiff = this.chars.indexOf(baseChar) - shiftIdx;
return (this.chars.charAt((shiftDiff< 0 ) ?
shiftDiff + this.chars.length : shiftDiff));
1
1
+
L a variable shiftsum es igual a 11 (8 3 ) .Asi, chars. charAt ( 11 sera la le-
tra 1.En este caso, sera el valor que devolvera substitute ( ) . Parece muy sen-
cillo. Y lo es, per0 supongamos que basechar es la letra o y que shiftldx es 30.
Revisemos las matematicas. Ahora shiftsum sera igual a 45. El problema es que
chars solo tiene 36 caracteres (a-z y 0-9). Por lo tanto, chars.charAt ( 4 5 ) no
existira.
Cuando el algoritmo llega a1 ultimo caracter de chars, debe continuar por el
principio, desde 0 y proseguir desde ahi con la suma. Podemos utilizar el opera-
dor de modulos para obtener el efecto deseado. Recordemos que este operador
devolvera un resto entero partiendo de dos operadores. Aqui tenemos varios
ejemplos :
Todo lo que tenemos que hacer es utilizar el operador de modulos. Asi, en vez
de utilizar u n shiftsum de 45, podremos utilizar shif tSum % chars.length,
que es igual a 9. chars. charAt ( 9 ) sera la letra j . Esto explica el codigo que uti-
liza el algoritmo de cifrado como comprobacion:
Muy sencillo. Sin cmbargo, si shiftDifles menor que 0, nos encontraremos con
el mismo problema que vimos cuando shiftsum era mayor que el resultado de
chars.length - 1. L a solucion sera sumarshiftDiffa chars.length. Perfec-
to. shiftDifl es negativo, es decir, que a1 sumar 10s dos campos obtendremos un
resultado (shiftDi;ff)menor que chars. length que es el indice que se anda bus-
cando con el fin de proceder con la desencriptacion.
El codigo que podemos ver a continuacion determina si substitute ( ) utili-
zara shiftDifl o shiftDifl+ chars. length como indice para proceder con la
desencriptacion:
return (this.chars.charAt((shiftDiff< 0 ) ?
shiftDiff + this.chars.length : shiftDiff));
document.layers['caesar'].document.forms[Ol.Shift.selectedIndex
document.forms[ll.Shift.selectedIndex
360 Cifrado en IavaScriDt
h t t p : / / w w w .microsoft.com/workshop/au thor/dhtmZ/reference/
objects.asp
Referencia para las hojas de estilos de Netscape y JavaScript para el cliente:
http://deveZoperl.netscape. com:8O/docs/manuals/communicator/
dynhtml/jss34.htm y http://deveZoper.netscape.com/docs/manuaZs/
js/cZien t/jsref/index.h tm
Algoritmo Vigenere
Es el mas sencillo de 10s dos. Vamos a ver VigenereAlgorithm ( ) . L a princi-
pal diferencia que hay es que el argumentoshiftldx que se pasa a substitute (
en caesarAlgorithm ( ) permanece constante. Con esta funcion, shiftldx podra
(y generalmente lo hace) cambiar con cada llamada a substitute ( ) . La otra
diferencia es que el usuario utilizara una palabra llave como llave en vez de un
numero. Este es el contenido de las lineas 96-1 19:
1
var keyword =
this.purify( (NN ?
refslide( "vigenere").document .forms [O] .KeyWord.value :
document.forms[2l.KeyWord.value));
if(!keyword 1 1 keyword.match(/\^s+$/) ! = null) {
alert('No valid keyword for ' +
(action ? 'ciphering.' : 'deciphering.'));
return false;
1
keyword = keyword.replace(/\s+/g, " ) ;
var keywordIdx = 0 ;
var cipherData = " ;
for (var i = 0; i < data.length; i++) {
shiftIdx = this.chars.indexOf(keyword.charAt(keyword1dx) ) ;
cipherData += this.substitute(data.charAt(i), shiftIdx, action);
keywordIdx = (keywordIdx == keyword.length - 1 ? 0 : keywordIdx +
1);
1
return cipherData;
1
Las cinco primeras lineas son iguales que las de caesarAlgori thm ( ) . Se en-
cargan del formato y validacion. Las siguientes lineas desarrollan una tarea
similar con la palabra que se usa como llave. Esta procede del campo del formu-
lario que se encuentra en la capa vigenere. No olvidemos que tenemos que adap-
tar la aplicacion para que trabaje con 10s DOM de Navigator y MSIE.
En Navigator, sera asi:
document.layer ['vigenere'l.document.forms[O].KeyWord.value
Y en MSIE, asi:
document.forms 21 .KeyWord.value
son ejemplos de palabras clave aceptables: gente, cielo, init2wnit o 1or2or.3. Per0
no se puede utilizar caracteres que no se encuentren en chars. No olvidemos que
purify ( elimina todos 10s caracteres distintos de a-z 6 0-9 y sustituye 10s
retornos de carro y grupos de espacios en blanco por un espacio en blanco. Aun-
que el usuario puede introducir l@@#derf t como una cadena, purify ( ) dara
formato y devolvera lderft que unicamente contiene caracteres validos. Va-
mos a considerar ahora las claves con espacios en blanco. De hecho, todos 10s
caracteres seran validos, a exception de 10s espacios en blanco. El contenido de
la linea 1 1 0 se encarga de eliminarlos:
var keywordIdx = 0;
var cipherData = ' I ;
Para cada caracter de 10s datos (ya estk el texto codificado o sin codificar), el
valor de shiftldx sera el indice de chars de keyword.charAt (keywordIdx). La
variable cipherData sera igual a si misma mas el valor que devuelva el metodo
substitute( ) , que recibe una copia dedata.charAt (i)yshi,ftldx,junto con
action.Al aumentar keyword& una unidad, se prepara el conjunto para la
siguiente repeticion.
Cifrado en JavaScript 363
Ahora, cada uno de 10s objetos Substitutioncipher que se ha iniciado tiene una
propiedad llamada chars y un metodo purify[). Es decir, que todos 10s objetos
Substitutioncipher serfin una versi6n mas especifica de Cipher.
Hasta ahora hemos visto la manera en la que trabajan 10s dos sistemas de en-
criptacion. A continuacion vamos a ver como crear 10s objetos que 10s represen-
tan y como se puede construir la interfaz por medio de la cual se interactua con
ellos. La creacion de 10s objetos no nos llevara mas que cuatro lineas, desde la
121 hasta la124:
var cipherArray = [
new SubstitutionCipher("caesar",caesar, CaesarAlgorithm),
new SubstitutionCipher("vigenere",vigenere, VigenereAlgorithm)
I;
364 Cifrado en JavaScript
De momento, nos vamos a centrar en cada una de las llamadas que se efectlian
a1 constructor Substitutioncipher( ) ,donde se entregan las cadenas adecua-
das, un nombre, una descripcion y una referencia a la funcion, a la que se asig-
narh la propiedad dgorithrn de cada objeto Substitutioncipher que se ha creado.
Asi se crean 10s objetos. Vamos a echar un vistazo a la interfaz. Es la parte del
codigo que se encontrarh entre las etiquetas BODY:
<DIV>
<TABLE BORDER=O>
<TR>
<TD ALIGN=CENTER COLSPAN=3>
<IMG SRC="images/cipher.j p g " >
Cifrado en JavaScript 365
</TD>
/ TR>
<TR>
<TD VALIGN=TOP WIDTH=350>
<FORM>
<SELECT NAME="Ciphers"
onChange="showCipher(this.options[this.selectedIndexl.value); " >
<OPTION VALUE="caesar">CaesarCipher
<OPTION VALUE="vigenere">Vigenere Cipher
< /SELECT>
</TD>
<TD ALIGN=CENTER>
<TEXTAREA NAME="Data" ROWS="15" COLS="40"
WRAP= PHYSICAL">< /TEXTAREA>
<BR><BR>
<INPUT TYPE=BUTTON VALUE="Encipher"
onClick="routeCipher(this.form.Ciphers.selectedIndex,
this.form.Data.value, true);">
<INPUT TYPE=BUTTON VALUE="Decipher"
onClick="routeCipher(this.form.Ciphers.selectedIndex,
this.form.Data.value, false); " >
<INPUT TYPE=BUTTON VALUE=" Reset
onClick="this. form.Data.value= ' ' ; " >
< I FORM>
< I TD>
< /TR>
</TABLE>
</DIV>
Este codigo crea una tabla de dos filas. En la superior colocara un grafico en
TD, utilizando COLSPAN con un valor de 2. La fila inferior contendra dos celdas.
La de la izquierda contiene una lista de selection como esta:
<SELECT NAME="Ciphers"
onChange="showCipher(this.options[this.selectedIndexl .value);">
<OPTIONVALUE="caesar">CaesarCipher
<OPTION VALUE="vigenere">Vigenere Cipher
</SELECT>
Esta lista determina la interfaz que se mostrara en pantalla. Como s610 hay
dos, sera una de ellas. El controlador de eventos onchange llamara a la funcion
showcipher ( ) , entregandole un valor que reflejara la opcion seleccionada. Esta
funcion es muy corta. La tenemos en las lineas 126-130:
function showCipher(name) {
hideSlide(curCipher);
showSlide(name1;
curcipher = name;
>
366 Cifrado en IavaScriDt
Este codigo nos puede resultar bastante familiar. Lo hemos visto en 10s capitu-
10s 3 y 6. Las funciones hideslide ( ) y showslide ( ) estan dentro dedhtrnljs.
Obskrvese que la celda de datos tendra u n ancho de 3 5 0 pixeles. Al contrario de
lo que ocurre con la lista de seleccion, la celda de datos aparecera vacia. Afortu-
nadamente, las dos capas se encargaran de rellenarla. En las lineas 180-181 te-
nemos las llamadas que se encargan de la creation. La funcion genLayer ( ) crea
las capas de 10s sistemas de encriptacion y tambikn la podemos encontrar den-
tro de dhtmLjs. Tambikn es una funcion que hemos visto en capitulos anterio-
res, por eso no le dedicaremos mhs tiempo:
Con estas dos sentencias se crea el texto que mostrara cada sistema de cifrado,
junto con la lista de seleccion de Caesar y el campo de texto de Vigenere. Como
ya hemos comentado, podemos cambiar el sistema de encriptacion (Caesar o
Vigenkre) a travks de la lista de seleccion que se encuentra en la parte superior de
la pantalla, y que mostrara el sistema con el que se trabajara.
Al igual que ocurre con la otra celda de la fila inferior de la tabla, contendra
una zona de texto y tres botones. Se encuentran en las lineas 161-1 70:
<TEXTAREA NAME= Data '' ROWS= 15 " COLS= 40 WRAP= " PHYSICAL'' >< /TEXTAREA>
I'
<BR><BR>
<INPUT TYPE=BUTTON VALUE="Encipher"
onClick="routeCipher(this.form.Ciphers.selectedIndex,
this.form.Data.value,true); " >
<INPUT TYPE=BUTTON VALUE="Decipher"
onClick="routeCipher(this.form.Ciphers.selectedIndex,
this.form.Data.value, false);">
<INPUT TYPE=BUTTON VALUE=" Reset onClick="this.form.Data.value=' ; " >
'I
Esta funcion acepta tres argumentos. Ya hemos hablado de 10s dos ultimos.
data es el contenido del campo de texto y action sera true o false.El primero,
cipherIdx, procede de document. forms [ 0 1 .Ciphers.selectedIndex. Tendra
que ser 0 6 1. Independientemente de su valor, el mCtodo algorithm ( ) del ob-
jetoSubstitutionCipher encipherArray se hace con una llamada. Si algorithm ( )
devuelve otro valor distinto de false,se tendra que preparar el texto para que
se encripte o desencripte.
docurnent.forrns[O].Ciphers.selectedIndex = 0 ;
Posibles ampliaciones
Aunque esta aplicacion es muy divertida para jugar con ella, el siguiente nivel
de aplicacion sera el envio de mensajes de correo. Podemos hacerlo en tres pasos.
En primer lugar, copiaremos Ia siguiente funcion y la pegaremos entre las eti-
quetas SCRIPT:
function sendText(data) {
parawidth = 70;
var iterate = parseInt(data.1ength / parawidth);
var border = '\n-------\n' ;
var breakData = " ;
for (var i = 1; i <= iterate; i + + ) (
breakData += data.substring((i - 1) * parawidth, i parawidth) +
'\r';
1
breakData += data.substring((i - 1) * parawidth, data.length);
docurnent.CipherMail.Message.va1ue = border + breakData + border;
368 Cifrado en IavaScriDt
document.CipherMail.action =
'"mailto:someone@somewhere.com\?subject=TheSecret Message";
return true;
I
FORM NAME= " CipherMail ACTION= '' METHOD= POST" ENCTYPE= text /plain"
I' 'I
onSubmit="return sendText(document.forms[0l.Data.value);"~
<INPUT TYPE=HIDDEN NAME="Message">
<INPUT TYPE=SUBMIT VALUE=" Send ">
< /FORM>
por esto:
por eso:
Tendremos que efectuar todos estos cambios puesto que, en el paso anterior,
hemos aiiadido otro formulario a lajerarquia. sendText ( ) determinara el valor
Cifrado en JavaScript 369
I U ! ~
scha
RV The Top Secret Message
Sat 20 May Lm0 11 3Y 21 10200
tt b n a C l e p d r r m u e u l r p l naqlumz b y t i z i p 2 01 i l y YIOLUOI
4e we Oaspef2 v y e p l d l n t l t 3 c l s u l n u p n3 LpndClml I eo 1 3e lnbrloln V
-
e5dO d t WP c
--
PD. Esta aplicacidn s610 funcionarh si el usuario tiene la funcidn de correo elec-
tronico de NN o MSIE correctamente configurado, que suele ser en la mayoria
de 10s casos.
CaPitulo 10
m
El fin de esta aplicacihes s6lo divertirse. Los usuarios podran enviar felicitacio-
nes personalizadas a sus familiares y amigos con simpaticos simbolos y un men-
saje. La figura 10.1 muestra la pantalla principal de la interfaz de la aplicaci6n.
Cyber Greetings
To I
Message 2.l
Cyber Greetings
o,"anelamlllD es
Images
Greenng
Sending
(figura 10.4).Si se hace clic en el, entonces el script enviara la tarjeta a la direc-
ci6n especificada.
Congratulations!
YO" hsvr PucccsrrWhr created a Cybn GRermaca
Isrls.h&p@olae 'IP ram M y o u h r ro do II s a d Imn or her m e-mal to
armomcc the p e t m g Just push &e buaoo below. md the c-md d be on the
R c m To Cytc_jie_cta%
Ahora el usuario puede leer el mensaje. (No tengo ningun tio Juan, por lo que
me he enviado el mensaje a mi propia cuenta de hotmail.) La figura 10.5 muestra
374 Cyber Greetings: arrastrar y soltar sobre el correo electronico
Analisis de la sintaxis
Con esta aplicacidn tambien empezaremos con el diagrama de flujo y despuCs
pasaremos a ver el codigo. En la figura 1 0 . 7 podemos ver que el usuario intro-
duce la direccidn del destinatario, el contenido del mensaje, selecciona un fondo
y coloca 10s iconos sobre la tarjeta. Luego podra ver el aspect0 de su trabajo. Si
esta satisfecho con 10s resultados, se lo envia a1 servidor.
Esta aplicacion trabaja a dos niveles: en el explorador del cliente y en el servi-
dor Web. El explorador es la herramienta que utiliza el usuario para crear el fon-
do, 10s iconos y el mensaje de la tarjeta. Cuando envia el formulario HTML, la
informacion la recibira el servidor Web, que se encargara de la creacion de un
archivo que coincida con la tarjeta. El servidor Web devolvera un formulario
HTML a1 usuario para que pueda enviar el mensaje a1 destinatario. Este mensaje
no contendra nada mas que un anuncio y un vinculo para que se pueda recoger
la tarjeta de Cyber Greeting.
Primero repasaremos la aplicacion desde el punto de vista del cliente y luego
desde el servidor. Hay cuatro archivos. Los vemos en la siguiente lista:
indexhtrnl. Nivel superior. Contiene 10s marcos de trabajo.
back.htmZ. Contiene el espacio de trabajo donde se selecciona la tarjeta, el
fondo y 10s iconos.
front.htmZ. Contiene la interfaz para crear y enviar el mensaje.
greet.pZ. Script del servidor que se utiliza para crear y almacenar las tarjetas
en un archivo y crear, a continuacion, un formulario HTML que se enviara
a1 destinatario.
Como se puede ver a traves de las capturas de pantalla, esta interfaz tiene dos
caras. La secundaria (backhtrnl) es la pantalla de la tarjeta donde el usuario
puede ver la tarjeta seleccionada y jugar con 10s elementos graficos. La principal
(front.html)contiene el formulario de entrada y es la que se encarga de la inser-
cion de la direccion de correo electronico y del cuerpo del mensaje y tambien de
3 76 Cyber Greetings: arrastrar y soltar sobre el correo electr6nico
la producci6n de 10s grhficos a 10s que se les conoce como iconos. Ambos docu-
mentos se encuentran dentro del archivo index.htrnZ. En el ejemplo 10.1 tene-
mos 10s detalles.
Selecciona el fond0
y coloca 10s iconos
selecciona una tau
I
Creacih del archivo Envlo
en el servidor de la tarjeta
a/ servidor
1 I
de la confimaci6n
y del formulano
del correo electrdnico
de un mensaje El destineiah
de correo electrdnico mbe el mensaje
a/ destinatano de correo electnsnrcu
I hXn.1
Figura 10.7. Logica de Cyber Greeting: pasos hasta que el destinatario lee el mensaje
7 var greetings = [
8 'Choose One', 'Family Reunion! I ,
1 <HTML>
2 <HEAD>
3 <TITLE>Cyber Greetings</TITLE>
4 < STYLE TYPE= text / cs s >
5 <!--
6
7 .Greeting
8 {
9 font-family: Arial;
10 font-size: 48px;
11 font-weight: bold;
12 1
11
14 //-->
15 </STYLE>
16 <SCRIPT LANGUAGE="JavaScript1.2">
17 <!--
18
19 var NN = (document.layers ? true : false);
20 var hideName = (NN ? 'hide' : 'hidden');
21 var showName = (NN ? 'show' : 'visible');
22 var zIdx = -1;
23
24 var iconNum = 4;
25 var startWdh = 25;
26 var imgIdx = 0;
27 var activate = false;
28 var activeLayer = null;
29
30 var backImgs = [ I :
31 var icons = [
32 'bear', 'cowprod', 'dragon', 'judo',
33 'robot', 'seniorexec', 'dude',' juicemoose',
34 'logol', 'logos', 'logo3','tree',
35 'sun', 'gator','tornado', 'cactus'
36 I;
37
38 function genLayout0 {
39
40 for (var i = 0; i <= 7; i++) {
41 backImgs[il = new Image();
42 backImgs[i].src = top.baseURL + '/images/background'+ i +
43 ,.jpg';
44 1
45
46 genLayer("Back", 10, 250, backImgs[l] .width,
backImgs [ 1I .height,
47 showName, <IMG NAME="background" SRC=" + top.baseURL +
48 '/images/backgroundO.jpg">');
Cyber Greetings: arrastrar y soltar sobre el correo electronico 3 79
49
50 for (var j = 0; j < parent.greetings.1ength; j++) (
51 genLayer("greeting" + j, 5 0 , 2 7 5 , 5 0 0 , 1 0 0 , hideName,
52 '<SPAN greeting">' + parent.greetings[jl + ' <
SPAN>') ;
53 1
54
55 for (var i = 0; i < icons.length; i++) {
56 if (i B iconNum == 0 ) ( startWdh = 2 5 ; )
57 else ( startWdh += 110; )
58 genLayer(icons[i], startWdh, 1 5 , 100, 100, (i < iconNum ?
showName :
59 hideName), <A HREF="javascript: changeAction(\' ' +
icons[il +
60 + (i + 1) + ' ) ; " x I M GSRC="' + top.baseURL +
I \ ' , '
78 copy + '</DIV>'
I9 );
80 1
81 1
82
83 function hideSlide(name) {
84 refSlide(name).visibility = hideName;
85
86
87 function showSlide(name) {
88 refSlide(name).visibility = showName;
89 I
90 function refSlide(name) I
92 if ( N N ) ( return document.layers[namel; )
93 else ( return eval('document.al1.'+ name + '.style'); 1
94 1
95
380 Cvber Greetings: arrastrar v soltar sobre el correo electronico
96 function motionlistener0 {
97 if (NN) I
98 window.captureEvents(Event.MOUSEM0VE);
99 window.onmousemove = grabXY;
100 1
101 else {
102 document.onmousemove = grabXY;
103 }
104
105
106 function grabXY(ev) {
107 if (activate) {
108 if(”) {
109 var itemwdh =
refSlide(activeLayer).document.images[Ol.width;
110 var itemHgt =
refSlide(activeLayer) .document.images[Ol .height;
111 refSlide(activeLayer).left = ev.pageX - parseInt(itemWdh /
2):
112 refSlide(activeLayer).top = ev.pageY - parseInt(itemHgt /
2) :
113 1
114 else {
115 var itemwdh = document.images[imgIdx].width;
116 var itemHgt = document.images[imgIdx].height;
117 refSlide(activeLayer).left = event.x - parseInt(itemWdh /
2):
118 refSlide(activeLayer).top = event.y - parseInt(itemHgt /
2):
119 1
120 }
1 21 1
122
123 function changeAction(name, MSIERef) {
124 activate = !activate;
125 activeLayer = name;
126 imgIdx = MSIERef;
127 )
128
129 //-->
130 </SCRIPT>
131 < /HEAD>
132 <BODY onLoad=”motionListener( ) : ” >
133
134 <SCRIPT L A N G U A G E = “ J a v a S c r i p t 1 . 2 ” >
135 <!--
136
137 genLayout () ;
138
139 //-->
140 < /SCRIPT>
Cvber Greetings: arrastrar v soltar sobre el correo electronico 381
Antes de que el remitente pueda crear la felicitation, una serie de funciones ten-
dran que generar una serie de capas y determinar la ubicacion del cursor del
raton, con respecto a1 documento. Es muy parecido a lo que se vio en 10s capi-
tulos 3 y 8. De hecho, varias funcionen proceden directamente de dichos capitu-
10s. Lo volveremos a comentar cuando las analicemos. De momento, vamos a
echar un vistazo a la declaracion de variables que tiene lugar en las lineas 19-36:
var iconNum = 4;
var startWdh = 25;
var imgIdx = 0;
var activate = false;
var activeLayer = null;
var backImgs = [ I ;
var icons = [
'bear', 3cowprod', 'dragon', 'judo',
'robot', 'seniorexec', 'dude', 'juicernoose',
'logol', 'log02'. 'logo3','tree',
'sun', 'gator', 'tornado', 'cactus'
I;
Las cuatro primeras funciones de la tabla son las mismas que las vistas en 10s
capitulos anteriores. Si no esta familiarizado con ellas, revise 10s capitulos espe-
cificados. Sin embargo, m o t ionListener ( ) se ha modificado ligeramente, por
lo que tendremos que analizarla. La funcion grabXY ( ) que se Vera en el siguien-
te capitulo tambiin ha sufrido algun cambio. A continuacidn veremos el resto
de funciones.
function genLayout0 {
Lo primero que hace genLayout ( ) es cargar por anticipado las imagenes del
fondo. Como el usuario querra verlas antes de decidirse por una de ellas, convie-
ne cargarlas antes. Al usar backlmgs, la funcion crea un objeto Image para cada
elemento, asigna su origen de acuerdo con t o p . baseURL (ya la hemos declara-
do en indexhtml), crea la cadena background, el valor de i y la cadena .jpg:
Cada elemento de 10s iconos representa una capa. La variable iconNurn deter-
mina que se mostraran cuatro iconos a la vez. Ademas, las imagenes tendran
100 pixeles de ancho. Los tamafios pueden variar. La variablestartWdh empieza
en 25. Este valor determinara la posicion del pixel izquierdo de las capas que se
van creando. He dejado una separaci6n de 10 pixeles entre 10s iconos. Es decir,
que si empezamos a 25 pixeles del margen derecho de la capa, colocaremos un
icono nuevo cada 110 pixeles (100 pixeles de ancho de la capa y 10 de separa-
cion entre ellas). Despues de crear y colocar el iconNurn de 10s iconos, el proceso
se inicia con el mismo punto de referencia de 10s 25 pixeles. Esto es posible gra-
cias a las propiedades de programacion. Una de ellas es la declaracion if-else que
se ejecuta antes de que la funcion genLayer ( ) se encargue de generar la capa;
la otra es la utilizacion del operador de modulos (%). Vamos a verlas con mas
detalle:
Cvber Greetinas: arrastrar v soltar sobre el correo electronic0 385
if ( i % i c o m u m == 0 ) { startWdh = 25; }
else { startWdh += 110; 1
Segun se ejecuta el bucle, i crece cada vez mas. Cada vez que i es multiplo de
iconNum (4, en este caso), se iniciara un nuevo grupo de iconos, colocando el pri-
mero a 25 pixeles de distancia del borde izquierdo de la capa. startWdh tendra el
valor 25. Por ejemplo, se iniciara un nuevo grupo de iconos cuando el valor de
i sea 4, 8, 12, 16 y 20. Si i es cualquier otro valor, se indicara que el siguiente
icono se colocara a 110 pixeles de distancia del icono anterior. Esta es la razon
por la que se aiiade 110 a1 valor de startWdh. El operador de modulo devolvera
un entero que indicara el resto del cociente. Si el resto es 0, i sera multiplo de
iconNum.
La parte mas complicada sera conocer donde se encuentra el borde izquierdo
de cada capa. Ahora genLayout ( ) completa sus tareas creando una capa para
cada icono junto con una llamada a genLayer ( ) :
Cada icono contiene una unica etiqueta IMG rodeada por otra etiqueta de refe-
rencia. ObsCrvese que el segundo y tercer argumento que se le pasa a genLayer ( )
seran 10s valores de las propiedades izquierda y superior de la capa. startWdh
siempre representa la izquierda; la parte superior sera siempre 15 pixeles. El sex-
to argumento que se pasa determina si el icono sera visible o no. Por defecto,
unicamente se mostrara el primer conjunto creado de iconos. En este caso, las
cuatro primeras capas. Por lo tanto, el operador condicional del sexto argumen-
to determinara que si i es menor que iconNum (por ejemplo, 0, 1, 2 6 3), la capa
sera visible. En cualquier otro caso, se ocultara. Si el icono ha de ser visible, se
pasara la variable showNarne. Si no, hideName se hara cargo de la llamada.
Los dos ultimos puntos que se han de tener en cuenta antes de seguir seran la
naturaleza de la etiqueta de referencia. iQu6 hace? Supongarnos lo siguiente.
Siempre que el usuario pase la raz6n sobre u n icono y haga clic una vez, la apli-
caci6n entendera que quiere moverlo. Para ello, el protocolo javascript : que
se encuentra dentro del atributo HREF se encarga de enviar una llamada a la
funcion changeAction ( ) , que veremos en breve. Todos 10s atributos HREF lla-
man a esta funcion, per0 cada enlace entregara a changeAction ( ) informacion
sobre si mismo.
En primer lugar, changeAction ( ) tendra que conocer el nombre del icono
con el que tiene que trabajar. Es sencillo. Se le entrega en icons [ i 1 , que contie-
ne la cadena correcta. A continuacion, tendremos que entregar u n entero que
386 Cyber Greetings: arrastrar y soltar sobre el correo electronico
function motionlistener0 {
if ( N N ) {
window.captureEvents(Event.MOUSEM0VE);
window.onmousemove = grabXY;
1
else {
document.onmousemove = grabXY;
1
1
activeLayer = name;
imgIdx = MSIERef;
)
iSe acuerda de las variables activate y activelayer? Las declaramos hace bastan-
te tiempo, a1 principio del documento. activate se inicia con el valor f a l s e que
(como pronto veremos con g r a b X Y ( ) ) no movera ninguna capa a1 desplazar el
cursor del ratbn. La primera vez que se llama a changeAction ( 1, activate pa-
Sara a t r u e , con lo que g r a b X Y ( ) entrara en acci6n. La capa seguira a1 cursor.
L a unica forma de detenerlo sera haciendo clic de nuevo. Esta vez cambiara el
valor de la variable activate por supuesto, por f a l s e . Se detendra la operaci6n
de arrastre.
LRecuerda como se disefio c h a n g e a c t i o n ( ) para pasar su valor en dos argu-
mentos? Uno es el nombre de la capa con la que se esta trabajando, que se asig-
nara a name. El otro es el indice de la imagen, a traves del cual se establecera la
referencia a la imagen que se encuentra en el document. images (accion valida
para MSIE). Este valor se asignara aMSIERef. El valor de activelayer sera el mis-
mo de name e imgIdx se configurara con el valor de MSIERef. Es todo lo que ne-
cesitamos para arrastrar 10s iconos, independientemente del explorador que se
estk utilizando.
func t on grabXY(ev) {
if (activate) {
f(") I
var itemWdh = refSlide(activeLayer).document.images[Ol.width;
var itemHgt = refSlide(activeLayer) .document.images[Ol .height;
refSlide(activeLayer).left = ev.pageX - parseInt(itemWdh / 2 ) ;
refSlide(activeLayer).top = ev.pageY - parseInt(itemHgt / 2 ) ;
1
else {
var itemWdh = document.images[imgIdxl.width;
var itemHgt = document.images[imgIdxl.height;
refSlide(activeLayer).left = event.x - parseInt(itemWdh / 2 ) ;
refSlide(activeLayer).top = event.y - parseInt(itemHgt / 2 ) ;
)
)
Para obtener la imagen tendremos que establecer una referencia que apunte,
primero a la capa adecuada, luego a1 documento y por ultimo a images [ 0 I (es
la unica imagen de la capa). En MSIE las cosas cambian:
En vez de asignar 10s valores 100 y 100 a las posiciones izquierda y superior,
aplicaremos 10s valores 50, 25, con lo que tendremos el punter0 en el centro del
icono. Para asegurarse de que el resultado de la division entre 2 es u n numero
entero, utilizaremos parseInt ( ) para quedarnos unicamente con la parte en-
tera de dicho resultado. Vamos a volver a mirar el codigo de grabXY ( ) . L a im-
plementacion en Navigator sera la siguiente:
1 <HTML>
2 <HEAD>
3 <TITLE></TITLE>
4 <STYLE TYPE="text/css">
5 <!--
6
7 TD
a (
9 font-family: Arial;
10 >
11
12 .Front
13 I
14 position: absolute;
15 left: 25;
16 top: 25;
17 width: 325;
ia border: lpx solid;
19 background: #ffffee;
20 J
21
22 //-->
23 < 1 STYLE>
24 <SCRIPT LANGUAGE="JavaScriptl.2">
25 <!--
26
27
28 var curGreet = iconIdx = 0;
29 var backgroundIdx = 0;
30 var bRef = parent.Back
31
32 function showGreeting(sel1dx) {
33 if (selIdx > 0 ) (
34 bRef.hideSlide("greeting" + curGreet);
35 bRef . showslide ( "greeting" + selIdx);
36 curGreet = selIdx;
31 )
38 }
39
40 function nextBackground0 {
41 backgroundIdx = (backgroundIdx == bRef.back1mgs.length - l ?
42 backgroundIdx = 0 : backgroundIdx + 1);
43 if(document.al1) {
44 bRef.document.background.src =
bRef.backImgs[backgroundIdxl.src;
45 }
46 else {
41 bRef . document.layers [ "Back"] . document.images [ 0 I . src =
48 bRef.backImgs[backgroundIdxl .src;
Cyber Greetings: arrastrar y soltar sobre el correo electronico 391
49 1
50 I
51
52 function nextIcons0 {
53 for (var i = bRef.iconNum * iconIdx; i < (bRef.iconNum *
iconIdx) +
54 bRef.iconNum; i++) {
55 if (i < bRef.icons.length && !onCard(i)) {
56 bRef.hideSlide(bRef.icons[il);
57 1
58 1
59 iconIdx = (iconIdx >= (bRef.icons.length / bRef.iconNum) - 1 ?
0 :
60 iconIdx + 1);
61 for (var i = bRef.iconNum * iconIdx; i < (bRef.iconNum *
iconIdx) +
62 bRef.iconNum; i++) {
63 if (i < bRef.icons.length)
64 bRef.showSlide(bRef.icons[il);
65 1
66 else { break; 1
67 1
68 )
69
70 function resetForm0 {
71 if (document.al1) {
72 bRef .hideslide( "greeting" +
73 document.EntryForm.Greetings.selected1ndex);
74 document.EntryForm.reset0;
75
76 else {
77 bRef .hideslide("greeting" +
78 document.layers["SetupForm"].document.EntryForm.Greetings
.selectedIndex);
79 document.layers["SetupForm"].document.EntryForm.reset~~:
80 I
81 1
82
83 function onCard(iconRef) {
84 var ref = bRef.refSlide(bRef.icons[iconRef]
85 var ref2 = bRef .refSlide("Back");
86 if(document.al1) {
87 if((parseInt(ref.left) >= parseInt(ref2.lef
88 (parseInt(ref.top) >= parseInt(ref2.top))
89 (parseInt(ref.left1 + parseInt(ref.width)
parseInt(ref2.left) +
90 parseInt(ref2.width)) & &
91 (parseInt(ref.top)+ parseInt(ref.height)
parseInt(ref2.top) +
92 parseInt(ref2.height))) {
93 return true;
392 Cyber Greetings: arrastrar y soltar sobre el correo electronico
94 1
95 )
96 else {
97 if((ref.left >= ref2.left) &&
98 (ref.top > = ref2.top) & &
99 (ref.left + ref.docurnent.images[O].width < = ref2.left +
100 ref2.document.images[O].width) & &
101 (ref.top + ref.document.images[Ol.height <= ref2.top +
102 ref2.document.images[0l.height)) {
103 return true;
104 I
105 1
106 ref.left = ((iconRef 8 bRef.iconNum) * 110) + bRef.startWdh;
107 ref.top = 15;
108 return false;
109 1
110
111 function shipGreeting(f0bj) {
112 if (fObj.Recipient.value == " " ) I
113 alert('You need an email address in the To: field');
114 return false;
115 I
116 else if (fObj.Message.value == " " ) {
117 alert ( "You need to type a Message. " ) ;
118 return false;
119 I
120 else if (fObj.Greetings.selected1ndex = = 0 ) {
121 alert('You need to choose a Greeting.');
122 return false;
123 }
124
125 f0bj.EntireMessage.value = genGreeting(f0bj);
126
127 fObj.BaseURL.value = top.baseURL;
128 return true;
129 1
130
131 f:unction testGreeting(f0bj) {
132 var msgStr = '<HTML><TITLE>Cyber Greeting Test Page</TITLE>' +
133 genGreeting(f0bj) + '<TABLE ALIGN="CENTER"><TR><TD><FORM>' +
134 '<INPUT TYPE=BUTTON VALUE=" OK
onClick="self.close(); " > ' +
135 '</FORM></TD></TR></TABLE></HTML>';
136 newwin = open(", I *'width=' + (
,
137 bRef.backImgs[backgroundIdx].width + 5 0 ) +
138 ',height=600,scrollbars=yes');
139 with(newWin.document) (
140 open ( ) ;
141 writeln(msgStr);
142 close();
143 )
Cyber Greetings: arrastrar y soltar sobre el correo electronico 393
144
145
146
147 function genGreeting(f0bj) {
148 var greetingIdx = fObj.Greetings.selected1ndex;
149 var msg = f0bj.Message.value;
150
151 msg = msg.replace(/\r+/g, " " ) ;
152 msg = msg.replace(/\n+/g, "<BR><BR>") ;
153
154 var msgStr = '<TABLE BORDER=O><TR><TD COLSPAN=2><FONT
FACE=Arial>' +
155 '<H2>Your Cyber Greeting</H2>To: ' + f0bj.Recipient.value +
156 '<BR><BR></TD></TR><TR><TD VALIGN=TOP><IMG SRC="' +
157 top.baseURL + /images/background'+ backgroundIdx + ' . jpg">
158 + '<DIV STYLE="position:relative;left:4O;top:-255;font
fami1y:Arial;' +
159 'font-size:48px;font-weight:bold;">' +
parent.greetings[greetingIdxl +
160 ' </DIV>' ;
161
162 var iconStr = " ;
163 for (var i = 0; i < bRef.icons.length; i++) {
164 if (onCard(i) {
165 iconStr += '<DIV STYLE="position:absolute;left:' +
166 bRef.refSlide(bRef.icons[i]).left + ';top:'+
167 (parseInt(bRef.refSlide(bRef.icons[il).top) -
168 (document.al1 ? 140 : 150)) + ';"><IMGSRC="' +
169 top.baseURL + '/images/'+ bRef.icons[i] + '.gif"></DIV>';
170 1
171
172
173 msgStr += iconStr + '</TD></TR><TR><TDWIDTH=' +
174 bRef.backImgs[backgroundIdxl .width + '><FONT FACE=Arial>' +
msg +
175 '</TD></TR></TABLE>';
176 return msgStr;
177 )
178
179 //-->
180 </SCRIPT>
181
182 < /HEAD>
183 <BODY onLoad="resetForm(); " >
184 <DIV ID="SetupForm" CLASS="Front">
185 <FORM NAME= " EntryForm"
186 ACTION="http://www.your_domain.com/cgi-bin/greetings/greet.pl"
187 METHOD="POST" TARGET="-top " Onsubmit=" return
shipGreeting(this);">
188 <INPUT TYPE=HIDDEN NAME='' Ent ireMeS sage >
189
394 Cyber Greetings: arrastrar y soltar sobre el correo electronico
197 To:
198 </TD>
199 <TD COLSPAN= 2 '' VALIGN="TOP">
I'
201 </TD>
202 </TR>
203 <TR>
204 <TD HEIGHT= 80 VALIGN="TOP">Message: < /TD>
'I
207 </TEXTAREA>
208 </TD>
209 </TR>
210 <TR>
211 <TD>Images:</TD>
2 12 <TD HEIGHT="40'' COLSPAN=" 2" >
213 <INPUT TYPE=BUTTON VALUE=" Icons - >
onClick="nextIcons( 1 ; " >
214
215 <INPUT TYPE=BUTTON VALUE="Backgrounds- > "
216 onClick="nextBackground( ) ;" >
217 </TD>
218 </TR>
219 <TR>
220 <TD>Greeting:</TD>
221 <TD HEIGHT='I 40 '' COLSPAN= 2 >
I'
241 onClick="testGreeting(this.form);">
242
243 <INPUT TYPE=BUTTON VALUE=" Clear 'I
Las variables
Aunque front.htmZ no tiene tantas variables como back.htrnZ, hay unas cuan-
tas en las lineas 28-30:
referencia a 10s d
",TO C P P in favnr rreanrln 1
Cyber Greetings: arrastrar y soltar sobre el correo electr6nico 397
398 Cyber Greetings: arrastrar y soltar sobre el correo electronico
function showGreeting(sel1dx) I
if (selIdx > 0 ) {
bRef .hideslide ("greeting" + curGreet) ;
bRef.showSlide("greeting" + selIdx);
curGreet = selIdx;
1
1
Del siguiente bloque merece la pena que nos fijemos en el contenido correspon-
diente a las lineas 225-231. Puesto que el explorador analiza el c6digo HTML, el
c6digo JavaScript que se ejecute creara la lista de selection utilizando para ello
el array de tarjetas que fueron definidas en index.htmZ. Vamos a verlo a conti-
nuacih:
function nextBackground0 {
backgroundIdx = (backgroundIdx == bRef.backImgs.length - 1 ?
backgroundIdx = 0 : backgroundIdx + 1);
if(document.al1) {
bRef.document.background.src = bRef.backImgs[backgroundIdxl .src;
else {
bRef . document. layers [ "Back"] .document.images [ 0 I . src =
bRef.backImgs[backgroundIdxl .src;
1
Las imagenes del fondo se cargan de antemano en las lineas 40-44 del archivo
back.html. Como 10s nombres siguen el conveniobackgroundO.jpg,background 1 j p g ,
background2.jpg, etc., podemos usar un entero, backgroundldx, junto con una
suma de cadenas, para repetir la ejecucion a travks de todas las imagenes. Cuando
se carga el documento, el valor de backgroundldx es 0. Cada vez que el usuario
haga clic en "Background- este valor se aumentara una unidad hasta que
->,'I
se agoten las imagenes a las que establecer la referencia. En otras palabras, cuan-
do backgroundIdx sea igual a t o p . Back. backImgs . l e n g t h - 1, se le devol-
Vera el valor 0 para que empiece otra vez desde el principio.
Podemos utilizar este valor para cambiar la propiedad src del objeto Image ade-
cuado. Como la imagen del fondo se encuentra en una capa, tendremos que
volver a ordenarlas para acceder de distintas formas a traves de 10s DOMs de
NN y MSIE.
Para MSIE, la imagen se considera una propiedad del objeto del documento:
top.Back.document.background.src
Para Navigator, tendremos que desplazarnos a travks del objeto del documento
que se encuentra dentro de la capa. Como el nombre de la capa es Back, el acceso
a la imagen deseada tendra el siguiente aspecto:
top.Back.document.layers["Back"l .document.images[Ol.src
la primera vez que utilizamos este sistema de repeticion. Ya lo vimos en 10s ca-
pitulos 3 y 8. Ahora el usuario podra moverse a traves de 10s fondos de la tarje-
ta. Necesitaremos algo parecido para 10s iconos. Aqui es donde nextIcons ( )
entra en accion, en las lineas 52-68:
function nextIcons0 {
for (var i = bRef.iconNum * iconIdx; i < (bRef.iconNum * iconIdx) +
bRef.iconNum; i++) (
if (i < bRef.icons.length & & !onCard(i)) (
bRef.hideSlide(bRef.icons[il);
I
I
iconIdx = (iconIdx > = (bRef.icons.length / bRef.iconNum) - 1 ? 0 :
iconIdx + 1);
for (var i = bRef.iconNum iconIdx; i < (bRef.iconNum * iconIdx) +
bRef.iconNum; i++) (
i f ( i < bRef.icons.length) (
bRef.showSlide(bRef.icons[il);
I
else ( break; }
I
I
El usuario se mueve a traves de 10s iconos, igual que hacia con 10s fondos, per0
ahora hace mas cosas aparte de cambiar la propiedad src de una imagen. Cada
icono es una imagen que tiene su propia capa. Por eso, a1 hacer clic en el b o t h
"Icons - ->I'se desarrollan mas acciones que antes. Ademas de ocultar las capas
que aparecen en la pantalla, tendremos que determinar la capa que se mostrara,
para lo cual tendremos que crear grupos.
No tiene mucho sentido que el usuario haga clic 20 veces para ver 20 iconos.
Resulta bastante aburrido y una auttntica pCrdida de tiempo. Como se puede
ver en las capturas de pantalla que aparecen a1 principio del capitulo, he agru-
pado 10s iconos de cuatro en cuatro. Independientemente del valor seleccionado,
el valor de la variable iconNum se determinara en la linea 24 de back.htmZ. Como
se encuentra en front.htmZ, la referencia del script sera top.Back.iconNurn. La
idea es mostrar iconNum iconos cada vez que el usuario haga clic en el boton
"Icons- ->" Si tenemos 20 iconos, el usuario esperara encontrarse con cinco
grupos. Obviamente, tambitn queremos facilitar la tarea de aiiadir y eliminar
iconos. Si eliminamos u n icono, el usuario se encontrara con cuatro grupos de
cuatro iconos y uno de tres. Es decir, que no tendremos que modificar el con-
tenido de nextlcons ( ) .
Es muy sencillo. Empezaremos por 10s cuatro primeros, luego 10s escondere-
mos y mostraremos 10s cuatro siguientes, y repetiremos el proceso hasta que
nos quedemos sin iconos. Entonces volveremos a empezar. Lo podriamos traducir
Cyber Greetings: arrastrar y soltar sobre el correo electronico 401
como "escondemos 10s cuatro antiguos y mostramos 10s cuatro nuevos". Vamos
a analizar la version en JavaScript. Para identificar cada grupo utilizaremos la
variable iconldx, cuyo valor original sera 0. El primer grupo estara asociado con
0; el segundo con 1, etc.
En el momento en que el usuario selecciona "Icons - ->" tendremos que ocultar
10s iconos asociados con iconldx:
Ya hemos ocultado 10s antiguos iconos, por lo que tendremos que acceder a1
siguiente grupo. Per0 antes, hemos de comprobar que no nos encontremos en el
ultimo grupo. Si es el caso, asignaremos el valor 0 a la variable iconldx. Si no,
aumentaremos el valor de iconldx una unidad. Lo vemos en las lineas 59-60:
Una repeticion mas y el nuevo grupo sera visible. Las lineas 6 1-6 7 contiene un
buclefor que se encarga de ello:
402 Cyber Greetings: arrastrar y soltar sobre el correo electronico
else { break; }
1
function onCard(iconRef) {
var ref = bRef.refSlide(bRef.icons[iconRefl);
var ref2 = bRef .refSlide ( "Back") ;
if(document.al1) {
if((parseInt(ref.left) >= parseInt(ref2.left)) &&
(parseInt(ref.top) >= parseInt(ref2.top)) &&
(parseInt(ref.left)+ parseInt(ref.width) <= parseInt(ref2.left) +
parseInt(ref2.width)) &&
(parseInt(ref.top) + parseInt(ref.height) <= parseInt(ref2.top) +
parseInt(ref2.height))) (
return true;
1
I
Cyber Greetings: arrastrar y soltar sobre el correo electronico 403
else {
if((ref.left >= ref2.left) &&
(ref.top >= ref2.top) &&
(ref.left + ref.document.images[Ol.width <= ref2.left +
ref2.document.images[O].width) & &
(ref.top + ref.document.images[Ol.height <= ref2.top +
ref2.document.images[O] .height)) {
return true:
J
1
ref.left = ((iconRef P; bRef.iconNum) * 110) + bRef.startWdh;
ref.top = 15;
return false;
1
Antes de entrar a ver mas de cerca la funci6n onCard ( ) , tendremos que saber
quC califica el icono que se encuentra en la zona de la tarjeta. En el caso mas
sencillo, todos 10s bordes del icono (aunque Sean transparentes) se encontraran
dentro de 10s limites de la imagen del fondo. La figura 10.8 nos demuestra lo
que ocurre.
. . . . . .
. . . . . .
. . . . . . ..' . ,. .... . .
, '
.. . . .,
~
. . . . . . . . . . .. . . .
Figura 10.8. Fuera de 10s limites. El unico que esta dentro es el karateca
Todo depende de la posicion de 10s pixeles. Como la imagen del fondo se encentra
dentro de una capa, podremos utilizar DHTML para determinar las posiciones
de su borde izquierdo y superior en relacion con 10s limites del documento. Como
la capa unicamente contiene una imagen, podremos utilizar las propiedades
width y height del objeto Image para determinar las dimensiones de la capa. Esto
mismo se cumple con 10s iconos. Utilizaremos las propiedades left y top de la
capa y width y height de Image. Esta funcion tiene un par de declaraciones if
anidadas, pero las clausulas if y else externas desarrollan basicamente la misma
accion, una para MSIE y otra para Navigator. Esta es la primera mitad de onCard ( 1,
la parte que funciona con IE:
if(document.al1) {
if((parseInt(ref.left) >= parseInt(ref2.left)) & &
(parseInt(ref.top) >= parseInt(ref2.top)) & &
(parseInt(ref.left) + parseInt(ref.width) < = parseInt(ref2.left) t
parseInt(ref2.width)) & &
(parseInt(ref.top) + parseInt(ref.height) <= parseInt(ref2.top) +
parseInt(ref2,height))) {
return true;
1
1
La imagen del fondo tiene cuatro bordes. Igual que el icono. Por lo tanto, ne-
cesitaremos cuatro comprobaciones para asegurarnos que 10s bordes del icono
se encuentran dentro de 10s limites de la imagen del fondo. Esta es la version
escrita de la declaracion if que se encuentra en las lineas 87-94:
Por otro lado, la funcion parseInt ( ) se encuentra por todos lados. MSIE de-
vuelve las propiedades Zeft y top en forma de cadenas de 250px en vez de 250.
parseInt ( ) convierte el valor de la cadena a u n ndmero, por lo que volvere-
mos a tirar de las matematicas.
L a clausula else externa desarrolla la misma accion, solo que esta vez para NN.
En realidad no tenemos que llamar a ParseInt ( ) porque Navigator devuelve
las propiedades top y Zeft como numero.
else i
if((ref.left >= ref2.left) &&
(ref.top >= ref2.top) &&
(ref.left + ref.document.images[O].width <= ref2.left +
ref2.document.images[O].width) & &
(ref.top + ref.document.images[O].height <= ref2.top +
ref2.document.irnages[O].height)) {
return true;
)
Asi que, si el icono en cuestion pasa 10s tres examenes, ambos exploradores de-
volveran true. En caso contrario, veremos quC pasa:
Probar el trabajo
Estaria bien que el remitente pudiese ver el aspect0 que tendra el mensaje cuando
lo reciba el destinatario. Para eso esta el boton "Test", que abre una ventana re-
mota donde lo muestra. Las lineas 131-145 tienen el cddigo del que hablamos:
function testGreeting(f0bj) {
var msgStr = '<HTML><TITLE>CyberGreeting Test Page</TITLE>' +
genGreeting(f0bj) + '<TABLE ALIGN="CENTER"><TR><TD><FORM>'+
406 Cvber Greetings: arrastrar v soltar sobre el correo electronico
Crear la tarjeta
testGreeting( ) proporciona una ventana para ver el contenido de la tarje-
ta. Sin embargo, genGreeting ( ) se encarga del trabajo interno.
Este es el contenido de las 31 lineas, 147-1 77:
function genGreeting(f0bj) {
var greetingIdx = f0bj.Greetings.selectedIndex;
var msg = f0bj.Message.value;
(parseInt(bRef.refSlide(bRef.icons[il).top) -
(document.al1 ? 140 : 1 5 0 ) ) + ' ; " > < I M G S R C = " ' + top.baseURL +
'/images/' + bRef.icons[iI + '.gif"></DIV>';
1
I
Se trata de una funcion algo compleja. Vamos a tratar de simplificar las cosas
examinandola desde el punto de vista de 10s objetos que se han de conseguir.
genGreeting ( ) es la unica que devolvera codigo HTML para representar 10s
siguientes puntos:
otra pagina, en la misma posicion relativa con respecto a la imagen del fondo
(basandose en las posiciones izquierda y superior). No olvidemos que la funcion
onCard ( ) determina la posicion del icono y, por lo tanto, la posibilidad de que
se seleccione.
El codigo generado para cada uno sera una etiqueta IMG que estara rodeada de
etiquetas DIV.Esta etiqueta sera el atributo STYLE que se haya asignado y la po-
sicion izquierda y superior absoluta del icono, menos 140 o 150 pixeles, depen-
diendo de si el explorador es Internet Explorer o Navigator. A continuacion, un
par de preguntas:
1. iPor quC puedo utilizar la posicion izquierda del icono como si ya hubiese
aplicado una cornpensacion de 100 pixeles en la posicion superior?
2. iPor quC sera diferente la cornpensacion de pixeles en cada explorador?
Buenas preguntas.
Vamos a empezar pensando en la ubicacion de la imagen del fondo de la interfaz
de la tarjeta. Se encuentra en la mitad inferior de la pagina, dependiendo de la re-
solucidn del monitor. Ahora pensemos en la posicion que tendra dentro de la
ventana de prueba. Se encuentra cerca de la parte superior de la pagina, justo
debajo de la cabecera y de la direction del destinatario. Los pixeles se encargaran
de compensar la diferencia. Si la imagen de fondo apareciese en la ventana de
pruebas en la misma posicion que en la interfaz de la aplicacion, no seria nece-
sario aplicar esta nueva ubicacion. Como hay una diferencia en la compensa-
ci6n de pixeles en ambos exploradores, cada uno parece que lo coloca en un
punto ligeramente distinto. La diferencia de 10 pixeles se encargara de corregirlo.
DespuCs de crear una capa donde colocaremos el icono, se sumara el valor de
iconStr a msgStr, junto con algo de codigo HTML y msg, con lo que se completa
la tabla de la aplicacion Cyber Greeting:
mSgStr += iconStr + ' < / T D > < / T R > < T R > < TWIDTH='
D +
bRef.backImgs[backgroundIdxl.width + '><FONT FACE=Arial>' + msg +
'</TD></TR></TABLE>';
return msgStr;
rnsg se insertara dentro de una celda de datos que tendra el mismo ancho que
la imagen de fondo (para optimizar el formato de la tarjeta). Se devuelve la ca-
dena completa.
Envio de la tarjeta
El usuario ha creado una tarjeta, ha comprobado su aspect0 final y esta con-
tento con 10s resultados. Todo lo que tiene que hacer ahora es clic en el b o t h
410 Cyber Greetings: arrastrar y soltar sobre el correo electronico
function shipGreeting(f0bj) {
if (fObj.Recipient.value == " " ) {
alert('You need an email address in the From: field');
return false;
I
else if (fObj.Message.value == " " ) {
alert ( "You need to type a Message. " ) ;
return false;
1
else if (fObj.Greetings.selected1ndex == 0 ) {
alert('You need to choose a Greeting.');
return false;
1
fObj.EntireMessage.value = genGreeting(f0bj);
fObj.BaseURL.value = top.baseURL;
return true;
1
Esta funcion es muy corta y se accede a ella a traves del controlador de eventos
onsubmit que se encuentra en la linea 1 8 7 . No solamente se limita a preparar
s h i p G r e e t i n g ( ) para que envie el formulario a un servidor Web, sin0 que
tambikn desarrolla una validacion rapida. Como el servidor sigue una serie de
sencillas instrucciones, la ejecucion del programa se desarrollara con suavidad.
Las unicas reglas que he impuesto es que el remitente ha de introducir una di-
recci6n electronica, escribir algo en el campo del mensaje y seleccionar un tipo
de tarjeta de la lista. Es posible que parezca un poco estricto, per0 nos ahorra-
mos problemas.
Si la informacion introducida pasa las pruebas, s h i p G r e e t i n g ( 1 cambia el va-
lor de 10s tres campos ocultos que se encuentran en las lineas 188-190. A 10s
campos EntireMessage, UniquelD y BaseLIRL, que originalmente contenian cade-
nas vacias, se les asigna la informacion que necesitara el script del servidor. Para
evitar que dicho script tenga que crear el codigo HTML de la tarjeta, se asigna a
E n t i r e M e s s a g e - v a l u e el resultados degenGreeting ( 1 . AUniqueID.value
se le asignara una cadena equivalente a u n numero aleatorio comprendido en-
tre 1 y 1.000.000.
Aparte del valor de dicho numero, se incluira en el nombre del archivo que se
utilizara para guardar la informacih de la tarjeta. SiUniqueID. v a l u e es 1 3 2 4 ,
el nombre bajo el que se guardara la tarjeta sera greetZ324.htmZ. No es compli-
cado, y este sistema nos permite crear cientos de miles de nombres unicos para
las tarjetas. La probabilidad de crear dos tarjetas con el mismo nombre es muy
pequeiia. El resto de la information que necesitara el script del servidor serh el
Cyber Greetings: arrastrar y soltar sobre el correo electr6nico 41 1
URL a1 que enviara la tarjeta, las imagenes del fondo y 10s iconos. Asi que a
BaseURL .value se le asigna el valor de t o p . baseURL. DespuCs de esto, se en-
viara el formulario a la direcci6n que se asign6 en el atributo ACTION degreet.pZ.
Lo podemos ver en la linea 186.
El servidor
Al igual que ocurria con mopping Cart ael capitulo 8, en esta aplicaci6n nece-
sitaremos trabajar con cierto mecanismo propio del servidor. Las tarjetas que
crea el usuario se generan utilizando el c6digo JavaScript del cliente. A conti-
nuaci6n se enviara esta informaci6n a un script del servidor Web, en un entor-
no de trabajo como Active Server Pages, Server-side JavaScript o Cold Fusion.
Este entorno de trabajo con script leer5 la informaci6n que envia el remitente
y creara un archivo unico donde guardara el c6digo de la tarjeta. Este archivo es
el que se envia a1 destinatario a travCs de un mensaje de correo electr6nico. El
archivo esta listo y esperando a que el destinatario utilice el vinculo que incluye
en el mensaje.
412 Cyber Greetings: arrastrar y soltar sobre el correo electronico
Posibles ampliaciones
Vamos a ver unas cuantas formas de mejorar esta aplicacion
Agregar temas
Esta aplicacion aclama imagenes de temas. Navidad, San Valentin, Verano o
cualquier otra cosa que se nos ocurra. Podemos utilizar fondos que representen
las estaciones del aiio e iconos que se adapten a ellos; o cumpleaiios, felicitacio-
nes variadas, etc.
Anuncios
Si va a permitir que sus usuarios utilicen esta aplicacion gratuitamente, ipor
qu6 no obtener algun beneficio de ello? En la funcion shipGreeting ( ) pode-
mos utilizar algun anuncio (banner) incluyendo el codigo correspondiente den-
tro de una etiqueta IMG. Si utilizamos 10s temas que hemos mencionado antes,
podremos asignar anuncios que estkn relacionados con ellos.
10s usuarios no tendran que buscar el archivo de ayuda deseado. Si tienen una
duda sobre el contenido de la pantalla, 10s archivos de ayuda contextual les
mostrarhn la respuesta.
Orange
Yellow
Indigo
Analisis de la sintaxis
Esta aplicaci6n se compone de una serie de archivos. Son 10s que aparecen a
continuaci6n:
41 6 Ayuda contextual
Excite
No vamos a entrar en 10s detalles propios de las listas de seleccion que hay de-
triis de 10s archivos background.htrnZ, multiseZect.htrn1 y urZdirectory.htm1. Ya lo
hemos visto en otros capitulos, asi que ahora 10s obviaremos. Asegurese de re-
pasar la publicaci6n de las listas que tiene lugar en el archivo rnultiseZect.htmZ.
Siempre serh de ayuda. En lo concerniente a nuestra aplicacih, nos moveremos
en dos fases:
Ayuda contextual
Es muy sencillo. Todo ocurre dentro de nav.htmZ. El ejemplo 1 1 . 1 nos muestra
el codigo.
6 <!--
7
8 A
9 {
10 text-decoration: none;
11 1
12
13 BODY
14 {
15 font-family: Arial;
16 text-align: center;
17 1.
18
19 //-->
20 </STYLE>
21 <SCRIPT>
22 < I --
23 var helpwin;
24
25 function inContext(currFi1e) {
26 var start = currFile.lastIndexOf('/')+ 1;
21 var stop = currFile.lastIndexOf('.');
28 var helpName = currFile.substring(start, stop
29 if(he1pWin == null I I helpWin.closed) {
30 helpwin = open('help/' + helpName + '.html' IhelpFile',
31 'width='+ top.wdh + ',height='+ top.hgt +
32 ',left=100,top=100,scrollbars=no');
33 1
34 else {
35 helpWin.location.href = 'help/' + helpName + '.html';
36 1
31 helpWin.focus();
38 1
39
40 //-->
418 Ayuda contextual
41 </SCRIPT>
42 <BODY>
43
44 < A HREF="background.html TARGET="WorkArea">BackgroundColors</A>
45
46 <A HREF= "urldirectory .html " TARGET= "WorkArea">URL Directory</A>
41
48 <A HREF= "mu1tiselect.html " TARGET= " WorkArea" >Multiple SELECT
Lists< /A>
49
50 <A HREF="javascript:
inContext(parent.WorkArea.location.href);"zHelp</A>
51
52
53
La funcion incontext ( ) trabaja con una premisa: todos 10s documentos con
10s que se vaya a mostrar la ayuda, precisaran un archivo con su mismo nom-
bre y la extension .htmZ.Es decir, el archivo background.htm1, el archivo que
muestra la forma en que se modifica el color del fondo, tendra un archivo de ayu-
da background.htrnZ en el directorio help/ (donde se guardan todos estos fiche-
ros). Las lineas 25-38 muestran 10s detalles:
function inContext(currFi1e) {
var start = currFile.lastIndexOf('/') + 1;
var stop = currFile.lastIndexOf('.');
var helpName = currFile.substring(start, stop);
if(he1pWin == null I I helpWin.closed) {
helpwin = open('help/' + helpName + '.html', 'helpFile', 'width=' +
top.wdh + ',height=' + top.hgt +
',left=100,top=100,scrollbars=no');
}
else {
helpWin.1ocation.href = 'help/' + helpName + '.html';
}
helpWin.focus0;
>
Esta funcion espera un URL como argumento. currFiZe puede ser un URL abso-
luto como http://some.pZace.com/some/document.htmZo un URL con una peti-
cion, como docurnent.cgi?search=all. De cada URL, nosotros s610 nos quedaremos
con el nombre. Descartaremos el nombre del host, dominio y directorios. Es de-
cir, nos quedaremos con todo lo que se encuentra desde de la ultima barra in-
clinada (/), si hay alguna, hasta el ultimo punto del URL (suponiendo que todos
10s nombres de archivos tendran una extension).
Por lo tanto, la variable start nos dara el indice de la dltima barra inclinada + 1.
Supongamos que el URL no tiene ninguna barra inclinada. N o ocurre nada. El
Ayuda contextual 41 9
ero no sr:
hlru
0
U C L l U l l d 31 LlCllC
una nu te alla:
42 0 Ayuda contextual
no se na iniciaao
ntonces incon text
Y
ado un obieto venta
true siempie que se cierre la'ven-
Por lo tanto, si if heZpWin.cZosed es
21 copy + '</DIV>'
22 );
23 >
24 >
25
26 function hideSlide(name) {
27 refSlide(name).visibility = hideName;
28 }
29
30 function showSlide(name) {
31 refSlide(name).visibility = showName;
32 1
33
34 function refSlide(name) {
35 if ( N N ) ( return dpcument.layers[namel; 1
36 else ( return eval('document.al1.' + name + '.style'); )
37 I
38
39 function motionListener0 (
40 if (NN) (
41 window.captureEvents(Event.MOUSEM0VE);
42 window.onmousemove = grabXY;
43 1
44 else {
45 document.onmousemove = grabXY;
46 I
41 >
422 Avuda contextual
48
49 function grabXY(ev) {
50 if(") {
51 x = ev.pageX;
52 y = ev.pageY;
53 1
54 else {
55 x = event.^;
56 y = event.y;
57 1
58 1
59
60 function helpDisplay(name, action) {
61 if(action) {
62 totalwidth = x + helpWdh;
63 totalHeight = y + helpHgt;
64 x = (totalwidth > opener.top.wdh ? x -
65 (totalwidth - opener.top.wdh + 7 5 ) : X I ;
66 y = (totalHeight > opener.top.hgt ? y -
67 (totalHeight - opener.top.hgt) : y ) ;
68 refSlide(name).left = x - 10;
69 refSlide(name).top = y + 8 ;
70 showSlide(name) ;
71 1
72 else { hideSlide(name); I
73 1
74
75 motionlistener();
Crear capas
Si ha revisado 10s capitulos 3, 4, 6, 7 6 9, estara familiarizado con las dos pri-
meras docenas de lineas de codigo. Si no lo ha hecho, es conveniente que repase
el contenido del capitulo 3 y revise 10s detalles de las funciones genLayer ( ) ,
hideslide ( 1, showslide ( ) y refslide ( ) . El proceso de creacion de capas
sera el mismo que ha visto en otros capitulos. Tendremos que aiiadir un paso
adicional. Las variables heZpWdh y heZpHgt tendran un valor de 200 pixeles cada
una. Son las encargadas de definir las dimensiones (ancho y alto) predetermina-
das de cada capa. Es muy importante porque necesitaremos esas variables (y
top.wdh y top.hg) para establecer posiciones en todo momento.
Estas funciones seran las herramientas que necesitaremos para crear las capas.
Todo lo que tendremos que hacer sera llamar a genLayer ( ) y entregarle el con-
tenido y el resto de variables. Todos 10s archivos de ayuda contienen una llamada
Avuda contextual 423
a esta funcion. C6mo se repite en todos 10s documentos, nos limitaremos a ob-
servar lo que ocurre en uno de ellos, por ejemplo, en heZp/background.htmZ:
.helpset
{
background-color: #CCFFCC;
padding: 5px;
border: 2px;
width: 200px;
font: normal lOpt Arial;
text-align: left;
1
function motionlistener() {
if ( N N ) {
window.captureEvents(Event.MOUSEM0VE);
window.onmousemove = grabXY;
1
424 Ayuda contextual
else {
document.onmousemove = grabXY;
1
Mostraremos la capa sin importar el vinculo que se haya utilizado. Para ello,
tendremos que determinar la posicion del cursor del raton en la pantalla y de-
tectar cuando pasa por encima de un vinculo. La funcion motionListener ( )
hace que el controlador de eventos onMouseMove llame a la funcion grabXY ( )
siempre que el usuario mueva el cursor. Tanto Navigator como MSIE pueden tra-
bajar con onMouseMove, per0 Navigator lo hace a travks del objeto window y
MSIE a travks del objeto document. Navigator t a m b i h necesitara una llamada
a1 mCtodo captureEvents ( ) para determinar el evento mousemove.
La funcion grabXY ( asigna las variables x e y a las coordenadas horizontal y
vertical (en pixeles) que tiene el cursor y las actualiza cada vez que este se mue-
ve por la pantalla. Aqui tenemos el contenido de las lineas 49-58:
function grabXY(ev) {
if(") {
x = ev.pageX;
y = ev.pageY;
1
else {
x = event.screenX;
y = event.screenY;
>
>
Estas coordenadas se implementan de distinto mod0 en MSIE y NN. Navigator 4
crea un objeto sobre la marcha para cada llamada que se haga a1 controlador de
eventos. El parametro ev determinara el objeto. Por otro lado, Internet Explorer,
tiene un evento propio. Llama a grabXY ( ) cada vez que el usuario mueve el ra-
ton, con lo que se actualizara constantemente el valor de las variables x e y.
Cuando el cursor se coloca sobre un vinculo, 10s valores de x e y establecerhn un
buen punto de referencia para mostrar capas con ayuda adicional.
Mostrar la informacion
Si el usuario pasa el cursor sobre un vfnculo, llama a la funcionhelpDisplay ( ) .
Este es el primer codigo HTML (de background.htmZ) que llama a la funcibn. A
continuacion aparece la propia funcion:
bgColor
</A>
helpDisplay ( ) espera dos argumentos. Uno sera el nombre de la capa que tie-
ne que mostrar/ocultar. El otro sera un valor booleano que determinara quC ha
de hacer con la capa. Lo primer0 que se determinarh sera si la capa se tiene que
mostrar u ocultar. Si action es f a l s e , el procedimiento sera muy sencillo. Bas-
tar5 con llamar a hideSli.de ( ) . si action es t r u e , habra que mostrar la capa.
LBastaria con llamar a showSli.de ( ) ? No. Es algo mas complicado.
evoluci6n de c
426 Avuda contextual
I aocumenro
El ancho y alto de cada capa sera de 200 pixeles. En realidad, la altura de la ven-
tana se ajusta sobre la marcha a la cantidad de contenido del documento, igual
que ocurre con las celdas de una tabla. Per0 aun necesitaremos una referencia.
No es necesario ser un experto en matematicas para darse cuenta de que si el
vinculo tiene un ancho superior a 10s 100 pixeles (algo menos, porque 10s 300
pixeles representan el ancho de la ventana, no el ancho del documento interior)
por lo menos habra una parte de la capa que no estara a la vista. Para evitarlo,
haremos unos cuantos cAlculos previos a la colocacion de la capa.
El funcionamiento es el siguiente: si la coordenada horizontal del rat6n mas el
ancho de la capa que se ha de mostrar es mayor que el ancho de la ventana re-
mota, la capa se mover6 a la izquierda un numero de pixeles para compensar.
Consideremos el contenido de la linea 62:
totalwidth = x + helpWdh;
. . .. . .. ., . .
. I .- .. .. .. .., . . ' . , . .. . ? ~-~ .* . .
Posibles ampliaciones
La aplicacih de ayuda que hemos visto en este capitulo posiblemente sirva con
la mayoria de aplicaciones de tamaiio medio-pequeiio. Per0 segun se vaya au-
mentando el tamaiio, necesitaremos mas propiedades. Vamos a considerar las
siguientes sugerencias a la hora de crear nuestra ayuda online.
Tabla de contenidos
Algunos usuarios buscan informacih que no esta relacionada con el context0
en el que se encuentran. Una de las formas m8s sencillas de facilitarles la labor
es crear una tabla de contenidos donde se muestren vinculos a todos 10s docu-
mentos de ayuda. Para ello, se puede utilizar una pi5gina HTML esthtica o c6di-
go JavaScript que se encargue de generarla sobre la marcha a partir de un array
de elementos:
function showcontents0 {
var helpDocs = ['background', 'multiselect', 'urldirectory'l;
var helpLinks = '<UL>';
for (var i = 0; i < helpDocs.length; i++) {
helpLinks += '<LI><A H R E F = " ' + helpDocs[il + '.html">' +
helpDocs[il + '</A>';
I
helpLinks = '</UL>';
Ayuda contextual 429
document.writeln(he1pLink.s);
1
Atencion telefonica
Si realmente quiere ofrecer un buen servicio a sus clientes, proporcione una lis-
ta con numeros de telkfono y direcciones de correo electronico para que puedan
ponerse en contact0 con seres humanos que se encargarhn de atender sus du-
das. Al igual que ocurre con 10s formularios basados en el correo electronico, este
tip0 de servicio requiere contar con 10s recursos adecuados. Asegurese que tiene
personal suficiente atendiendo las llamadas telefonicas Habrh gente que llamarh.
Epilog0
Esta es otra de las razones por las que queria mi propio libro. DespuCs de avan-
zar, pagina a pagina, hasta el ultimo capitulo de la una de esas publicaciones
Web, con una extension unicamente comparable a la Santa Biblia o a Guerra y
Paz, iqut suele haber? Unos cuantos apendices y el indice. Esta bien. Per0 es como
escalar hasta lo alto de una montaiia y no tener otra cosa que hacer que mirar
hacia abajo. LDonde esta el mkrito?
Si llegado a este punto echa la vista atras, Vera que ha andado un largo cami-
no, que no se ha limitado a pasar una pagina tras otra. Piense en lo que sabia de
codigo JavaScript cuando cornpro el libro. Piense ahora en todo lo que ha apren-
dido. Uno se siente bien cuando es testigo de sus logros y es consciente del ca-
mino que le ha guiado hasta la cima.
Obviamente, podemos disfrutar de nuestro Cxito, per0 no estaremos demasia-
do comodos. L a tecnologia cambia a una velocidad vertiginosa. En el momento
en que este libro llegue a su estanteria, 10s desarrolladores habran mejorado las
tCcnicas y extensiones de JavaScript. Voy a revisar su codigo ASAP: Si desarrolla
una aplicacion que merezca la pena, no dude en decirmelo. iNos vemos en la
Red!
-Jerry Brandenbaugh
hotstyle@mail.serve. com
Apendice A
Referencia de JavaScript
En general, trabaja con una estructura de tres capas: nucleo, cliente y servidor.
El ndcleo de JavaScript hace referencia a esas propiedades que se pueden utilizar
tanto en el servidor como en el cliente. Los lados cliente y servidor incluyen una
serie de extensiones propias de un entorno determinado. Por ejemplo, en el lado
del cliente en JavaScript contiene la ventana y 10s objetos document, elementos
que no puede utilizar el servidor. Del mismo modo, el c6digo JavaScript del lado
del servidor contiene el objeto File.
El material que veremos aqui pertenece a la version 1 . 3 de JavaScript para el
cliente y a1 nucleo de JavaScript 1.4.El contenido de las siguientes paginas se ha
extraido directamente del sitio Web de Netscape:
ht tp://developerl .netscape.com:8O/docs/manuals/js/core/jsref/index.
htm
h ttp://developerl.netscape.com:80/docs/manuals/js/client/jsreJ/index.h t m
La informacion sobre Microsoft Jscript la encontrara en la siguiente direccion:
http://msdn.microsoft.com/scripting/default.htm?/scripting/jscript/default.h t m
Tenga esta informacion a mano, ya que las puede necesitar para efectuar una
consulta rapida. En cualquier caso, en las direcciones de Microsoft y Netscape
encontrara las ultimas novedades.
Anchor
Un punto del docurnento a1 que seiiala un vinculo de hipertexto. Con la etique-
ta A en HTML, o mediante la llarnada a1 metodo String.anchor,el motor de ru-
tinas de JavaScript crea un objeto Anchor que se corresponde con cada etiqueta A
del documento que tiene el atributo NAME. Coloca estos objetos en la propiedad
document.anchors dentro de u n array. Para acceder a un objeto Anchor, indexa-
remos dicho array. Para acceder a un objeto Anchor, indexaremos dicho array.
Compatibilidad
JavaScript 1.O / cliente.
Resumen del mktodo
Este objeto hereda 10s mktodos watch y unwatch de Object.
Applet
La etiqueta HTML <APPLET>. El motor de rutinas de JavaScript crea u n objeto
Applet que se corresponde con cada uno de 10s applet que aparecen en el docu-
mento. Coloca estos objetos en un array en la propiedad docurnent.appZets. Para
acceder a un objeto Applet, indexaremos dicho array.
Compatibilidad
JavaScript 1.1 / cliente.
Resumen de propiedades
El objetoApplet hereda todas las propiedades publicas del applet de Java applet.
Las propiedades se detallan en la tabla A.2.
Referencia de IavaScriDt 435
Area
Define u n Area de una imagen o u n mapa de imageries. Cuando el usuario hace
clic en ella, la referencia del hipervinculo se carga en la ventana de destino. Los
objetos Area son del tip0 Link.
Compatibilidad
JavaScript 1.1 / cliente.
Array
Permite trabajar con arrays.
Compatibilidad
JavaScript 1.1 / nucleo.
Boolean
El objeto Boolean se utiliza con 10s valores booleanos.
Compatibil idad
JavaScript 1.1 / nucleo.
Referencia de JavaScript 437
Resumen de propiedades
Las propiedades de Boolean se detallan en la tabla A.4.
Resumen del mtftodo
Los mttodos de Boolean se detallan en la tabla A.5.
Tabla A.4. Propiedades de Boolean
Button
Boton de un formulario HTML.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur, onclick, onFocus, onMouseDown, onMouseUp.
Resumen de propiedades
Las propiedades se detallan en la tabla A.6.
Resumen del mktodo
Los mttodos se detallan en la tabla A.7. Ademas, este objeto hereda 10s mtto-
dos watch y unwatch de Object.
438 Referencia de IavaScriDt
Checkbox
Una casilla de verificacion de un formulario HTML. Una casilla de verificacion
es un interruptor que puede activar y desactivar el usuario.
Compatibilidad
JavaScript I .O / cliente.
Controladores de eventos
onBlur,onclick,onFocus.
Resumen de propiedades
Las propiedades se detallan en la tabla A.8.
Resumen del me'todo
Los mttodos se detallan en la tabla A.9. Ademas, este objeto hereda 10s mtto-
dos watch y unwatch de Object.
Tabla A.8. Propiedades de Checkbox
Document
Contiene informaci6n sobre el documento y proporciona mktodos para mos-
trar la salida HTML a1 usuario.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onclick, onDblClick, onKeyDown, onKeyPress, onKeyUp, onMouseDown,
onMouseUp.
Resumen de propiedades
Las propiedades se detallan en la tabla A. 12.
Resumen del mktodo
Los mttodos se detallan en la tabla A. 13. Ademas, este objeto hereda 10s mkto-
dos watch y unwatch de Object.
Tabla A.12. Propiedades de Document
Event
Es el objeto que contiene una serie de propiedades las cuales describen u n even-
to de JavaScript. Estas propiedades se pasan como argument0 de un controla-
dor de eventos en el momento en que Cste tenga lugar.
Compatibilidad
JavaScript 1.2 / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.14. No todas las propiedades se co-
rresponden con todos 10s tipos de eventos.
446 Referencia de JavaScript
Tabla A. 14.Propiedades
Fileupload
Compatibilidad
JavaScript 1.O / cliente.
Se refiere a1 elemento de actualizacion de u n archivo del formulario HTML. El
elemento de actualizacion del archivo permite que el usuario suministre un archi-
vo como cadena de entrada.
Controladores de eventos
onBlur,onchange,onFocus.
Resumen de propiedades
Las propiedades se detallan en la tabla A.15.
Resumen deZ me'todo
Los mCtodos se detallan en la tabla A. 16. Ademas, este objeto hereda 10s mCto-
dos watch y unwatch de Object.
Tabla A.15. Propiedades de Fileupload
Form
Permite que 10s usuarios introduzcan texto y seleccionen elementos del formu-
lario, tales como casillas de verificacion, botones de opcion y listas de seleccibn.
Tambikn se puede utilizar u n formulario con la finalidad de publicar datos en
un servidor.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onReset, onsubmit.
Resumen de propiedades
Las propiedades se detallan en la tabla A. 17.
Resumen del mktodo
Los mktodos se detallan en la tabla A.18.
Frame
Una ventana puede mostrar, en una misma pantalla, varios marcos indepen-
dientes, cada uno con su propio URL. Para crear estos marcos se utiliza la eti-
queta FRAME dentro de <FRAMESET>.Los marcos pueden apuntar a distintos
URL y estar relacionados con URL independientes, todo dentro de la misma pan-
talla. Un conjunto de marcos componen una pagina. El objeto Frame se utiliza
para constituir estos marcos. En cualquier caso, JavaScript representa un mar-
co a traves de un objeto window. Cada objetoFrame es a su vez u n objeto window
por lo que contendra todas sus propiedades y metodos. Existen unas pocas dife-
rencias entre una ventana que constituye un marco y una ventana que sea de
orden superior. Para completar informacion sobre 10s marcos, consulte la sec-
cionwindow.
Compatibilidad
JavaScript 1.O / cliente.
Function
Determina una cadena de c6digo en JavaScript la cual se compilara como una
funcion.
Cumpatibilidad
JavaScript 1.1 / nucleo.
Resumen de propiedades
Las propiedades se detallan en la tabla A. 19.
Resumen del mtftodo
Los metodos se detallan en la tabla A.20.
450 ~
Referencia de IavaScriDt
Hidden
Se trata de un objeto Text que se suprime de la representacion del formulario
HTML en la pantalla. El objeto Hidden se utiliza fundamentalmente con la fina-
lidad de proporcionar 10s pares nombre/valor en el momento en que se envia el
formulario.
Compatibil idad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.2 1.
Resumen del mktodo
Este objeto hereda 10s mktodos watch y unwatch de Object.
History
Contiene un array de informacion acerca de todos 10s URL que han sido visita-
dos por el cliente desde una ventana. Esta informacion se guarda generalmente
en una lista a la que se puede acceder a traves del menu Ir a correspondiente a1
explorador.
Compatibilidad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades correspondientes aparecen detalladas a continuaci6n en la ta-
bla A.22.
Resumen del mktodo
Los metodos se detallan en la tabla A.23. Este objeto hereda 10s metodos watch
y unwatch de Object.
452 Referencia de JavaScript
Image
Referencia a una imagen del formulario HTML.
Compatibilidad
JavaScript 1.1/ cliente.
Controladores de eventos
onAbort, onError,onKeyDown,onKeyPres s,onKeyUp,onload.
Resumen de propiedades
Las propiedades se detallan en la tabla A.24.
Resumen del mitodo
Los mktodos se detallan en la tabla A.25. Este objeto hereda 10s metodos watch
y unwatch de Object.
Tabla A.24. Propiedades de Image
Java
Objeto de alto nivel utilizado para acceder a cualquier clase de Java del paque-
te j a m . *. El objeto Java se utiliza como sinonimo de la propiedad Packagexjava.
Compatibilidad
JavaScript 1.1.
J avaArray
Array de Java a1 que se accede desde el c6digo JavaScript, sera del tip0 JavaArray.
Compatibilidad
JavaScript 1.1 / nucleo.
Resumen de propiedades
Las propiedades se detallan en la tabla A.26.
Resumen del mdtodo
Los mktodos se detallan en la tabla A.27.
Tabla A.26. Propiedad JavaArray
JavaClass
Una referencia JavaScript a la clase Java. Un objeto JavaClass es una referen-
cia a una de las clases del paquete Java, comonetscape. j a v a s c r i p t .JSObj e c t .
Un objeto JavaPackage constituye una referencia a un paquete de Java, como
n e t s c a p e . j a v a s c r i p t . En JavaScript, lajerarquia JavaPackage y JavaClass
refleja el paquete Java y la jerarquia de clases.
Compatibilidad
JavaScript 1.1/ nucleo.
Resumen de propiedades
Las propiedades del objeto JavaClass constituyen campos estaticos de la clase
Java.
Resumen del mktodo
Las propiedades del objeto JavaClass son mCtodos estaticos de la clase Java.
Java0bject
Pertenece a1 tip0 de objeto Java a1 que se accede desde el c6digo de JavaScript.
El objeto JavaObject es un ejemplo de la clase Java que se ha creado o pasado a
JavaScript. JavaObj e c t es un contenedor de la clase; todas las referencias que se
hagan a ella se efectuan a travCs deJavaObject. Cualquier dato Java que se impor-
ta a JavaScript se convertira a 10s tipos propios de JavaScript. Cuando se devuel-
ve el objetoJavaObject a Java, se extrae del contenedor para que lo pueda utilizar
el c6digo Java.
Compatibilidad
JavaScript 1.1 / nucleo.
Resumen de propiedades
Las propiedades de JavaPackage son 10s objetos JavaClass y cualquier otro
objeto JavaPackage que contenga.
Referencia de JavaScript 455
J avaPackage
En Java, un paquete es una coleccion de clases de Java o de otros paquetes de
Java. Por ejemplo, el netscape contiene el paquete netscape. javascript;
este paquete contiene las clases JSObject y JSException.
En JavaScript, JavaPackage es una referencia a1 paquete de Java. Por ejem-
plo, una referencia a netscape es un objeto JavaPackage.netscape. javascript
es un objeto JavaPackage y una propiedad de netscape JavaPackage.Un
objeto JavaClass es una referencia a una de las clases del paquete, tales como
netscape. javascript .JSObject. Lajerarquia de JavaPackage JavaClass
muestran el paquete de Java y la jerarquia de la clase. Aunque 10s paquetes y
clases contenidos en JavaPackage son sus propiedades, no podremos utilizar
una declaration for. . . in para numerarlos como hacemos con las propiedades
de otros objetos.
Compatibilidad
JavaScript 1.1 / nucleo.
Resumen de propiedades
Las propiedades de JavaPackage son 10s objetos JavaClass y cualquier otro
objeto JavaPackage que contenga.
Layer
Corresponde a una capa de la pagina HTML y ofrece u n mod0 de manipularla.
Compatibilidad
JavaScript 1.2 / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.28.
Resumen del mktodo
Los mCtodos se detallan en la tabla A.29. Este objeto hereda 10s mCtodos watch
y unwatch de Object.
Tabla A.28.Propiedades de Layer
link
Por medio de las etiquetas HTMLA o AREA,o llamando a1 metodo String.link,
El motor de rutinas de JavaScript crea un objeto Link que se corresponde con
cada etiqueta A y AREA del documento que sustituye a1 atributo HREF. Coloca
estos objetos en un array en la propiedad document.Zinks. Para acceder c1 un ob-
jeto Link, indexaremos dicho array.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
Los objetos Area tienen 10s siguientes controladores de eventos: onDblClick,
onMouseOut, onMouseOver.
Los objetos Link cuentan con 10s siguientes controladores de eventos: onClick,
onDblClick,onKeyDown,onKeyPress,onKeyUp,OnMouseDown,onMouseOut,
onMouseUp,onMouseOver.
Resumen de propiedades
Las propiedades se detallan en la tabla A.30.
Referencia de JavaScript 459
Location
Contiene informacion del URL.
Compa t ibi 1idad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.32.
460 Referencia de JavaScript
Compatibilidad
JavaScript 1.O / nucleo.
Resumen de propiedades
Las propiedades se detallan en la tabla A.34.
Referencia de JavaScript 461
MimeType
Se trata de u n tipo MIME (Multipart Internet Mail Extension) que soporta el
cliente.
Compatibilidad
JavaScript 1.1 / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.36.
Resumen del mktodo
Este objeto hereda 10s metodos watch y unwatch de Object.
Referencia de JavaScript 463
Navigator
Permite trabajar con valores numkricos. El objeto Number es un objeto que se
utiliza como contendedor de 10s valores numkricos primitivos.
Compatibilidad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.37.
Resumen del mAodo
Los mktodos se detallan en la tablaA.38. Este objeto hereda 10s mktodos watch
y unwatch de Object.
Tabla A.37. Propiedades de Navigator
Netscape
Objeto de alto nivel utilizado para acceder a cualquier clase de Java del paque-
te netscape.*. netscape es un objeto de alto nivel predefinido en JavaScript. Se
puede acceder automaticamente a tl sin utilizar un constructor o llamar a un
metodo.
Compatibilidad
JavaScript 1.1 / nucleo.
Number
Permite trabajar con valores numtricos. El objeto Number es un objeto que se
utiliza como contendedor de 10s valores numericos primitivos.
Compatibilidad
JavaScript 1.1/ nucleo.
Resumen de propiedades
Las propiedades se detallan en la tabla A.39.
Referencia de JavaScript 465
Object
Obj ect es un tipo primitivo de JavaScript. Todos 10s objetos de JavaScript des-
cienden de Object. Es decir, 10s objetos de JavaScript contendran 10s mktodos
definidos para Objec t .
466 Referencia de JavaScript
Compatibilidad
JavaScript 1.0 / nucleo
Resumen de propiedades
Las propiedades se detallan en la tabla A.41
Resumen del me'todo
Los mCtodos se detallan en la tabla A.42.
Tabla A.41. Propiedades de Object
Option
Se corresponde con una de las opciones de la lista SELECT,
Compatibilidad
JavaScript 1.1 / cliente.
Referencia de JavaScript 467
Resumen de propiedades
Las propiedades se detallan en la tabla A.43.
Resumen del mktodo
Los mktodos se detallan en la tabla A.44. Este objeto hereda 10s metodos w a t c h
y unwatch de Object.
Packages
Objeto de alto nivel utilizado para acceder a cualquier clase de Java desde el
codigo de JavaScript.
Compatibilidad
JavaScript 1.1 / nucleo.
Resumen de propiedades
Las propiedades correspondientes aparecen detalladas a continuacion en la ta-
bla A.45.
468 Referencia de JavaScript
Password
Un campo de texto de u n formulario HTML que oculta su valor detras de una
serie de asteriscos (*). Cuando un usuario introduce un texto en un campo, 10s
asteriscos (*) ocultan la entrada.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur,onFocus.
Resumen d e propiedades
Las propiedades se detallan en la tabla A.46.
Resumen del mktodo
Los mttodos se detallan en la tablaA.47. Este objeto hereda 10s mttodos watch
y unwatch de Object.
Plugin
Modulo complementario instalado en el cliente. Los objetos plugin son objetos
predefinidos de JavaScript a 10s que se accede a traves del array navigatorplugins.
El modulo Plugin es un complemento instalado en el cliente. Un complemento
constituye un modulo de software que puede llamar el explorador para mostrar
datos incluidos dentro del propio explorador o tipos especiales.
Compatibilidad
JavaScript 1.1 / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.48.
Tabla A.48. Propiedades de Plugin
______~ ~
Radio
Boton independiente que pertenece a u n conjunto de botones de opci6n de un
formulario HTML. El usuario puede seleccionar uno de 10s botones de opcion
que se muestren en una lista de estos elementos.
Referencia de JavaScript 469
Plugin
Modulo complementario instalado en el cliente. Los objetos plugin son objetos
predefinidos de JavaScript a 10s que se accede a travks del array navigator.plugins.
El modulo Plugin es un complemento instalado en el cliente. Un complemento
constituye un modulo de software que puede llamar el explorador para mostrar
datos incluidos dentro del propio explorador o tipos especiales.
Compatibilidad
JavaScript 1.1 / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.48.
Tabla A.48. Propiedades de Plugin
Compatibilidad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades correspondientes aparecen detalladas a continuacion en la ta-
bla A.49.
Resumen del me'todo
Los metodos se detallan en la tabla A.50 Este objeto hereda 10s mktodos watch
y unwatch de Object.
Tabla A.49. Propiedades de Radio
RegExp
Objeto de una expresion regular que contiene el modelo de dicha expresion.
Tiene propiedades y mktodos para utilizar la expresion regular parq localizar y
sustituir elementos de una cadena. Ademas de las propiedades de una expresion
regular individual que se puede crear usando el constructor RegExp, 10s objetos
Referencia de JavaScript 471
Screen
Compatibilidad
JavaScript 1.O / cliente.
Resumen de propiedades
Las propiedades se detallan en la tabla A.55.
Tabla A.5 5. Propiedades de Screen
Select
Una lista de seleccion de u n formulario HTML. El usuario puede seleccionar
uno o varios de 10s elementos que aparecen en la lista, dependiendo de las con-
diciones bajo las que se crease la lista.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur, onchange, onFocus.
Resumen de propiedades
Las propiedades se detallan en la tabla A.56.
Resumen del mktodo
Los metodos se detallan en la tabla A.5 7. Este objeto hereda 10s metodos watch
y unwatch de Object.
Tabla A.56. Propiedades de Select
String
Un objeto que representa una serie de caracteres de una cadena.
Compat ibil idad
JavaScript 1.O / nucleo.
Resumen de propiedades
Las propiedades se detallan en la tabla A.58.
Resumen del rnktodo
Los mktodos se detallan en la tabla A.59. Este objeto hereda 10s mktodos watch
y unwatch de Object.
Tabla A.58. Propiedades de String
Submit
Se corresponde con el boton "Enviar"de formulario HTML. Este b o t h hace que
se envie el formulario a1 servidor.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur, onclick, onFocus.
Resumen de propiedades
Las propiedades se detallan en la tabla A.60.
Resumen del mAodo
Los mktodos se detallan en la tabla A.61. Este objeto hereda 10s methMds watch
y unwatch de Object.
sun
Objeto de alto nivel utilizado para acceder a cualquier clase de Java del paque-
te sun. *. Sun es un objeto de alto nivel predefinido en JavaScript. Se puede ac-
ceder automaticamente a 61 sin utilizar un constructor o llamar a un mitodo. El
objeto sun se utiliza como sinonimo de la propiedad Packages.sun.
Compatibilidad
JavaScript 1.1 / nucleo.
Text
Constituye un campo de insertion de texto de un formulario HTML. En un
campo de texto, el usuario puede introducir una palabra, una frase o una serie
de numeros.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur, onchange, onFocus, onselect.
Resumen de propiedades
Las propiedades se detallan en la tabla A.62.
Resumen del mAodo
Los m6todos se detallan en la tabla A.63. Este objeto hereda 10s m6todos watch
y unwatch de Object.
480 Referencia de IavaScrilst
Textarea
Campo de insercion de varias lineas de un formulario HTML. En un area de
texto, el usuario puede introducir palabras, frases o numeros.
Compatibilidad
JavaScript 1.1 / cliente.
Controladores de eventos
onBlur, onchange,onFocus,onKeyDown,onKeyPress,onKeyUp,onSe1ect .
Resumen de propiedades
Las propiedades se detallan en la tabla A.64.
Resumen del mktodo
Los mktodos se detallan en la tabla A.65. Este objeto hereda 10s mktodos watch
y unwatch de Object.
Tabla A-64. Propiedades de Textarea
Window
Representa una ventana o un marco del explorador. Es el objeto de nivel supe-
rior de 10s grupos Location, History y de 10s documentos.
Compatibilidad
JavaScript 1.O / cliente.
Controladores de eventos
onBlur,onDragDrop,onError,onFocus,onload,onMove,onResize,y tam-
biCn onunload.
Resumen de propiedades
Las propiedades se detallan en la tabla A.66.
Resumen del mktodo
Los mCtodos se detallan en la tabla A.67. Este objeto hereda 10s mCtodos watch
y unwatch de Object.
~ ~~
Controladores de eventos
Esta seccion contiene la sintaxis correspondiente a 10s 2 3 controladores de even-
tos de JavaScript.
onAbort
Controlador de eventos para Image.Ejecuta el codigo en JavaScript cuando se
anula un evento; es decir, cuando el usuario anula la carga de una imagen (por
ejemplo, haciendo clic en u n enlace o en el boton "Detener").
Compatibilidad
JavaScript 1 . 1 .
Referencia de JavaScript 487
Propiedades
onAbort tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
onBlur
Controlador de eventos para Button,Checkbox,Fileupload,Layer,Password,
Radio,Reset,Select,Submit,Text,Textarea y Window.Ejecuta el codigo
en JavaScript si hay u n evento blur; es decir, si 10s elementos de u n formulario
dejan de estar activos porque se desactiva la ventana o marco que 10s contiene.
Compa tibi 1idad
JavaScript 1 .O.
Propiedades
onBlur tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
onchange
Ejecuta el c6digo en JavaScript cuando tiene lugar u n evento change; es decir,
cuando un campo Select,Text o Textarea de u n formulario deja de estar ac-
tivo porque se ha modificado su valor. Controlador de eventos para FileUpload,
Select,Text y Textarea.
Compatibilidad
JavaScript 1.O.
Propiedades
onchange tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
onDblClick
Controlador de eventos para Document y Link. Ejecuta el codigo en JavaScript
cuando tiene lugar u n evento DblClick; es decir, cuando se hace doble clic sobre
alguno de 10s objetos del formulario o sobre un vinculo.
Compatibilidad
JavaScript 1.2.
Propiedades
onDblClick tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
LayerX, layerY, pageX, pageY, screen)(, screenY. Representa la ubicacion
que tiene el cursor en el momento en que ocurre el evento.
Which. Representa con un 1 el clic con el b o t h izquierdo del raton y con
un 3 el clic con el boton derecho.
Modifiers. Contiene una lista con 10s modificadores principales que se man-
tendran activos mientras el evento tenga lugar.
onDragDrop
Controlador de eventos para Document y Link. Ejecuta el c6digo en JavaScript
cuando tiene lugar u n evento DragDrop; es decir, cuando el usuario arrastra un
objeto en la ventana del explorador, como ocurre con 10s archivos.
Compatibilidad
JavaScript 1.2.
Referencia de JavaScript 489
Propiedades
onDragDrop tiene las siguientes propiedades:
onError
Ejecuta el codigo en JavaScript en el caso de que tenga lugar un evento error;
es decir, en 10s casos en que la carga de u n documento o de una imagen provoca
un error.
Compatibilidad
JavaScript 1.1.
Propiedades
onDragDrop tiene las siguientes propiedades:
onFocus
Controlador de eventos para Button,Checkbox,Fi leUpload,Frame,Layer,
Password,Radio,Reset,Select,Submit,Text,Textarea y Window.Ejecu-
ta el codigo en JavaScript cuando tiene lugar un eventofocus; es decir, cuando
se activa una ventana, cuadro, marco de trabajo o uno de 10s elementos de un
formulario.
Compatibilidad
JavaScript 1.O.
Propiedades
onFocus tiene las siguientes propiedades:
onKeyDown
Controlador de eventos para Document,Image,Link y Textarea.Ejecuta el
codigo en JavaScript si tiene lugar un evento KeyDown; es decir, cuando el usua-
rio pulsa una tecla.
Cornpatibizidad
JavaScript 1.2.
Propiedades
onKeyDown tiene las siguientes propiedades:
onKeyPress
Controlador de eventos para Document,Image,Link y Textarea.Ejecuta el
codigo en JavaScript si tiene lugar u n evento Keypress; es decir, cuando el ~isiia-
rio mantiene pulsada una tecla.
Compatibilidad
JavaScript 1.2.
Propiedades
onKeyPress tiene las siguientes propiedades:
onKeyUp
Controlador de eventos para Document,Image,Link y Textarea.Ejecuta el
codigo en JavaScript si tiene lugar u n evento KeyUp;es decir, cuando el usuario
suelta una tecla.
Compatibilidad
JavaScript 1.2.
Propiedades
onKeyUp tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
LayerX, layerY, pageX, pageY, screen)(, screenY. Para u n evento que tiene
lugar en una ventana, representa la ubicacion que tiene el cursor en el mo-
mento en que ocurre el evento. Para un evento que tiene lugar en un formu-
lario, representa la posicion del elemento de dicho formulario.
Which. Muestra el valor ASCII correspondiente a la tecla pulsada. El me-
todo String.f romCharCodese usa para obtener la tecla, numero o simbo-
lo que se corresponde conla tecla pulsada. El metodostring . charCodeAt
se utiliza para obtener el codigo ASCII correspondiente con la tecla que ha
sido pulsada.
Modifiers. Contiene una lista con 10s modificadores principales que se man-
tendran activos cuando el evento tenga lugar.
onload
Controlador de eventos para Image, Layer y Window. Ejecuta el codigo en
JavaScript cuando tiene lugar un evento load; es decir, cuando el explorador
completa la carga de una ventana o de todos 10s marcos que se encuentran den-
tro de una etiqueta <FRAMESET>.
Compatibilidad
JavaScript 1.O.
492 Referencia de JavaScript
Propiedades
onLoad tiene las siguientes propiedades:
Type. Indica el tip0 de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
Width, height. Represetan el ancho y alto de la ventana en la que tiene lugar
el evento (siempre y cuando no ocurra dentro de un marco).
onMouseDown
Controlador de eventos para Button, Document y Link. Ejecuta el c6digo en
JavaScript cuando tiene lugar u n evento MouseDown; es decir, cuando el usua-
rio pulsa uno de 10s botones del raton.
Cornpatibilidad
JavaScript 1.2.
Propiedades
onMouseDown tiene las siguientes propiedades:
Type. Indica el tip0 de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
LayerX, layerY, pageX, pageY, screen)<,screenY. Representa la ubicaci6n
que tiene el cursor en el momento en que ocurre el evento MouseDown.
Which. Representa con un 1 el clic con el b o t h izquierdo del rat6n y con
u n 3 el clic con el b o t h derecho.
Modifiers. Contiene una lista con 10s modificadores principales que se man-
tendran activos mientras el evento tenga lugar.
onMouseMove
Como el rat6n se mueve con tanta frecuencia, por defect0 onMouseMove no
sera evento de ningun objeto. Se ha de asociar con un objeto determinado. Eje-
cuta el codigo en JavaScript cuando tiene lugar u n evento MouseMove; es decir,
cuando el usuario mueve el cursor.
Cornpatibilidad
JavaScript 1.2.
Propiedades
onMouseMove tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
Referencia de JavaScript 493
onMouseOut
Controlador de eventos para Layer y Link. Ejecuta el codigo JavaScript cuan-
do tiene lugar un evento Mouseout; es decir, cada vez que el puntero abandona
u n area (dentro de la imagen del cliente) o u n enlace que se encuentra dentro de
otro enlace o zona activa.
Compatibilidad
JavaScript 1.2.
Propiedades
onMouseOut tiene las siguientes propiedades:
Type. Indica el tip0 de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
LayerX, layerY, pageX, pageY, screen)(, screenY. Representa la ubicacion
que tiene el cursor en el momento en que ocurre el evento Mouseout.
onMouseover
Controlador de eventos para Layer y Link. Ejecuta el codigo JavaScript cuan-
do tiene lugar un evento Muuseover; es decir, cada vez que el puntero pasa por
encima de un objeto o de un Area, procedente de cualquier punto que sea exte-
rior a ellos.
Compatibil idad
JavaScript 1.2.
Propiedades
onMouseOver tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envi6 originalmente el evento.
LayerX, layerY, pageX, pageY, screenX,screenY. Representa la ubicacion
que tiene el cursor en el momento en que ocurre el evento Mouseover.
onMouseUp
Controlador de eventos para Button, Document y Link. Ejecuta el c6digo en
JavaScript cuando tiene lugar u n evento Mouseup; es decir, cuando el usuario
suelta uno de 10s botones del ratbn.
494 Referencia de IavaScriDt
Compatibilidad
JavaScript 1.2.
Propiedades
onMouseUp tiene las siguientes propiedades:
9 Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
LayerX, layerY, page)<, page\(, screen)<,screenY. Representa la ubicacion
que tiene el cursor en el momento en que ocurre el evento Mouseup.
Which. Representa con u n 1 el clic con el boton izquierdo del raton y con
u n 3 el clic con el boton derecho.
W. Contiene una lista con 10s modificadores principales que se mantendran
activos cuando el evento tenga lugar
onMove
Controlador de eventos para Window. Ejecuta el c6digo en JavaScript cuando
tiene lugar un evento move; es decir, cuando el usuario o el script pasa a una ven-
tana o marco.
Compatibilidad
JavaScript 1.2.
Propiedades
onMove tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
ScreenX, screenY. Representa la posicion de la esquina superior izquierda
de la ventana o del marco.
onReset
Controlador de eventos para Form. Ejecuta el c6digo en JavaScript cuando tie-
ne lugar un evento reset; es decir, si un usuario borra el contenido del fomulario
(hace clic sobre el boton "Borrar").
Compatibilidad
JavaScript 1.1.
Propiedades
onReset cuenta con las dos propiedades que podemos ver detalladas a conti-
nuacion:
Referencia de JavaScript 495
onResize
Controlador de eventos para W i n d o w . Ejecuta el codigo en JavaScript cuando
tiene lugar un evento resize; es decir, cuando el usuario o el script modifican el
tamaiio de una ventana o marco.
Compatibilidad
JavaScript 1.2.
Propiedades
onResize tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
Width, height. Representa la altura de la ventana o del marco.
onselect
Controlador de eventos para Text y Textarea.Ejecuta el codigo en JavaScript
cuando tiene lugar un evento select; es decir, cuando el usuario selecciona parte
del contenido de un campo o zona de texto.
Compatibilidad
JavaScript 1 .O.
Propiedades
onselect tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
onsubmit
Controlador de eventos para Form. Ejecuta el codigo en JavaScript cuando tie-
ne lugar un evento submit; es decir, cuando el usuario envia un fomulario.
Compatibilidad
JavaScript 1 .O.
Propiedades
onsubmit cuenta con las dos propiedadesque podemos ver detalladas a conti-
nuacion:
496 Referencia de JavaScript
onunload
Controlador de eventos para Window. Ejecuta el codigo en JavaScript cuando
tiene lugar u n evento submit; es decir, cuando el usuario envia un fomulario.
Compa tibilidad
JavaScript 1.O
Propiedades
onunload tiene las siguientes propiedades:
Type. Indica el tipo de evento.
Target. Indica el objeto a1 que se envio originalmente el evento.
Apendice B
Web Resources
Referencia a JavaScript
Estos URL me han sido de gran ayuda durante 10s ultimos meses. Igual que me
han ayudado a mi, pueden ayudar a cualquier otro. En ellos encontrara mate-
rial de referencia, tutoriales, scripts, articulos, etc. sobre JavaScript.
DHTML Reference
Siempre es conveniente conocer la ultima inforrnacion existente sobre DHTML.
La mayor parte de 10s articulos de estas paginas tratan temas relacionados con
IE y NN.
DevHead dHTML:
http://www.zdnet.corn/devhead/filters/dhtml/
Dynamic HTML Zone:
h ttp://www.d h trnlzone.corn/index.h trn1
Dynamic Drive:
h ttp://www.dynamicdrive.com/
Inside DHTML:
http://www.insidedhtrnl.com/
The Dynamic Duo:
http://www.dansteinrnan.corn/dynduo/
Dynamic HTML Guru Resource:
http://www.h trnlguru.corn/
500 Web Resources
w ebmonkey/dynamic-html:
h ttp://www. hotwired. com/webmonkey/dynamic-h tml/
Frequently Asked Questions About Dynamic HTML:
http://www. microsoft.com/workshop/author/dhtml/dh tmlqa.asp
Perl/CGI Reference
Si quiere saber mas sobre Common Gateway Interface y Perl, empiece por aqui.
Los recursos de Perl son tan grandes e impresionantes como el propio lenguaje.
Asegdrese de bajarse e instalar todos 10s modulos para que funcionen bien.
Perl.com :
h ttp://www.perl.com/pace/pub
Perl Reference Page:
h t tp://reference.perl.com/query. @?section =tutorials
An Introduction to The Common Gateway Interface:
h t tp://www. u toronto.ca/webdocs/CGl/cgi I . h tml
Graphics Resources
Parece que dltimamente 10s caminos de JavaScript y de 10s graficos se cruzan
con demasiada frecuencia. Por eso he incluido la siguiente lista de URL. En ella
encontrara articulos y graficos gratuitos.
Cooltype. com :
ht tp://cool type.webpedia. com/
AndyArt:
http://www.andyart.com/
Web Resources 501
Aplicaciones sirnilares
En esta seccion encontrara enlaces con sitios Web que contienen aplicaciones
similares a las vistas en este libro.
Examenes online
Aunque hay que buscar mucho, la verdad es que en la Web tambien hay prue-
bas escritas con JavaScript. He encontrado las siguientes.
D2 Test:
http://inetpubl.com/psy/psy.htm
Esta prueba de concentracih, creada por Inet Publishing, utiliza JavaScript para
medir la concentration del usuario y contabilizar sus aciertos contrarreloj .
Hardware Fundamentals Practice Test:
http://www.cit.ac.nz/smac/hflOO/testIs. htm
Esta prueba es muy interesante. Examina 10s conocimientos que se tienen so-
bre el formato y particiones de disco, la capacidad de almacenamiento de estas
unidades, etc. Lo mejor de todo es que esta aplicacion nos permite saber, en el
502 Web Resources
Diapositivas
A continuacion mostramos algunas de las aplicaciones interesantes relaciona-
das con las secuencias de imagenes.
Project Management: A Slide Show:
h t tp://www.geocities.corn/-mohan-iyer/slideshow. h t m
Esta aplicacion DHTML tiene diapositivas animadas. Los graficos tardan un poco
en cargar, pero la espera merece la pena. El codigo JavaScript responsable se en-
cuentra en el archivo slideshow.js.
web blazonry:
http://blazonry.com/javascript/slideshow/
Esta diapositiva muestra la evolucion del sitio Web de mkaz, presumiblemente
desde sus comienzos. Puras y simples secuencias de imagenes.
Apartment Home Animated Virtual Tour:
http://www. mark-taylor. com/virtual tour/index.h t m
Estas diapositivas automatizadas guian a1 usuario en una visita por un piso. La
diapositiva tarda bastante en cargar. Pero el desarrollador tambien lo ha tenido
en cuenta e intenta entretenernos para que no hagamos clic en ningun lado.
Web Resources 503
Generador de secuencias
L a Red esta llena de aplicaciones especializadas en secuencias de imagenes. iPor
quk no darse una vuelta por alli y ver quC contienen?
The Mighty Mouseover Machine:
http://builder.cnet.com/Programming/Kahn/Ol28 98/index. html
Posiblemente, el sitio Web de Charity Khan tiene mas visitas que Builder.com.
Su aplicacion utiliza una ventana remota para crear una plantilla de imagenes
y crear automaticamente el c6digo correspondiente.
OnMouseOver Whipper:
h ttp://wsabstract. com/mousewhipper/index. h tm
504 Web Resources
Bibliotecas
La verdad es que no he encontrado mucho sobre las bibliotecas en JavaScript.
Las que aparecen en esta seccion cuentan con bastante codigo DHTML. Si dispo-
ne de algun tiempo libre, bajese estas librerias y trate de imaginarse el c6digo. Es
posible que termine por perder alguna neurona, per0 merecera la pena.
DHTMLLib Version 2:
h ttp://www. insidedhtml.com/dhtmllib/pagel .asp
Esta libreria procedente de InsideDHTML.com se ha construido para varios ex-
ploradores. Se basa en el modelo de objetos de MSIE, por lo que podrA escribir co-
digo para N N y MSIE (es decir, para ambos modelos de objetos).
FreeDOM:
h t t p : / / w w w . builder.com/Programm ing/FreeDOM/
Esta biblioteca de C I Net permite crear y manipular objetos JavaScript fuera
del contexto de 10s DOM.
The JavaScript Menu Component:
http://developer. netscape.com/viewsource/smith-menu/smith-menu.html
Bibliotecas para Netscape (menu.js)que permiten agregar menus flotantes con
varios submenus. iHe dicho que se pueden usar con varios exploradores? Echele
u n vistazo.
JavaScript DHTML Collapsible Lists:
h ttp://developer. netscape. com/docs/technote/dynhtml/collapse/index.html#
xbrowser
Este codigo permite organizar estructuras similares a la del arbol de directo-
rios del Explorador de archivos de Windows, con las que organizar y enlazar el
contenido de la Web. Incluso encontrara un generador de codigo que le permiti-
ra crear DHTML.
Web Resources 505
ScriptBuilder.com:
http://www.scriptbuilder.com/netobjects/library. nsf/By +language
Este almacen de script de Netobjects esta lleno de codigo listo para pegar en
cualquier aplicacion. No todo se encuentra en archivos .js, per0 esto se puede
cambiar con un editor de texto.
Cookies
Los dos vinculos siguientes conducen a un conjunto de aplicaciones basadas en
cookies. Las hay desde muy sencillas hasta bastante complicadas, material su-
ficiente como para estar entretenido durante un buen rato.
Cookie Demos:
h t t p : / / w w w . cookiecentral.com/demomain. h t m
Esta pagina contiene una lista de enlace con demostraciones de cookies per-
tenecientes a Cookie Central. Aplicaciones especializadas en configurar las pre-
ferencias de 10s usuarios, contabilizar el numero de visitantes o bien detectar el
explorador del usuario.
Shopping Cart Using Cookies:
h ttp://www. ozemail.com.au/-dcrombie/cartdemo/index. html
Aqui aprenderemos a aplicar las cookies a 10s carros de la compra. Se puede
combinar con la aplicacion vista en el capitulo 8.
Carros de la compra
Los carros de la compra escritos en JavaScript no son ninguna novedad. A con-
tinuacion tiene una lista con varios de ellos. Todos, a excepcion de 10s dos pri-
meros, son gratuitos.
Shop@ssitant:
ht tp://www.jZoyd.co.uk/
Esta aplicacion comercial dispone de una serie de propiedades y ventajas para
10s compradores virtuales. La ha desarrollado un grupo de "gurus"de JavaScript,
per0 no se asuste.
Shopmaster :
h ttp://www. shopmaster.net/shopmaster/shop. h t m
Las versiones de demostracion de 10s carros de la compra que encontrara en es-
tas paginas Web son muy robustas. Cuentan con un conjunto de imagenes en
miniatura con las que se puede visualizar su aspecto, informacion, etc.
506 Web Resources
Encriptadores
L a Web esta llena de sitios repletos de informacion sobre encriptacih. Per0 muy
pocos trabajan con JavaScript. Si encuentra alguno, aparte de 10s que mostra-
mos en esta lista, por favor, digamelo.
Ciphers by Gordon McComb:
h ttp://gmccomb.com/commerce/frame.html
Este sitio Web viene de la mano de uno de 10s primeros autores que ha escrito
algo sobre JavaScript. Merece la pena fijarse en 10s ejemplos de cifrado y protec-
cion con contrasefia que ha desarrollado utilizando JavaScript.
RSA Algorithm JavaScript Page:
h t tp://www.orst.edu/dept/honors/makmu r/
Esta introduccion, la cual cuenta con varias paginas, a1 mundo de la encriptacion
a RSA muestra la manera en que se puede implementar un formulario (muy ba-
sico) de RSA mediante la utilizacion de JavaScript. Merece la pena que desempolve
sus conocimientos de Eactorizacion de numeros primos si tiene pensado exami-
nar este codigo.
Web Resources 507
Ciphers en JavaScript:
ht t p / / w w w .serve.com/hotsyte/ciphers/
Obviamente, se trata de mi sitio Web. Esta aplicacion cubre la encriptacion por
sustitucion y transposicion.
Ayuda contextual
Aun no he encontrado ninguna aplicacion de ayuda online en la Web como la
descrita en el capitulo 1 1 . En cualquier caso, en 10s siguientes vinculos encon-
trara buen material. Cada uno de ellos utiliza su propio codigo para generar efec-
tos diferentes pero a la vez muy parecidos.
The Microsoft Home Page:
h t t p : / / w w w .microsoft.com/ms. htm
Aparte de la pagina principal, 10s desarrolladores de Microsoft han incluido lis-
tas expandibles dentro de nav. Cada una de estas listas contiene una serie de
vinculos dirigidos a otras paginas.
The JavaScript Menu Component:
http://developer.netscape.com/viewsource/smith-menu/smith-menu.html
Este articulo muestra el proceso de creacion de menus DHTML independientes
del explorador similares a 10s que hay en la pagina Web de Microsoft. Su autor,
Gary Smith, trabaja con u n sistema orientado a objetos muy interesante.
The Menu Toolkit:
h t t p : / / w w w .insidedh tml.com/constsets/menus/menubar.asp
Esta version de demostracion procede de uno de 10s multiples conjuntos de he-
rramientas DHTML que se han publicado en la Web. Revise todo el codigo.
Apendice C
Scripts en Per1
PerI/CG I
Per1 es u n acronimo de Practical Extraction and Report Language. Original-
mente se diseiio para manipular archivos y cadenas de texto, per0 en breve tam-
b i h se empleo para administrar las tareas del sistema y para crear contenidos
para la Web de forma dinarnica. Las raices de este lenguaje de programacion las
encontramos en C, sed, awk y sh.
Perl/CG I
Perl es un a c r h i m o de Practical Extraction and Report Language. Original-
mente se disefio para manipuIar archivos y cadenas de texto, per0 en breve tam-
b i h se empleo para administrar las tareas del sistema y para crear contenidos
para la Web de forma dinamica. Las raices de este lenguaje de programacion las
encontramos en C, sed, awk y sh.
Per0 Perl tambien se esta utilizando en otras areas, como por ejemplo:
Para ampliar Java, C, VisualBasic, Delphi y otros codigos.
En las aplicaciones XML (Extensible Markup Language).
Como PerlScript, u n motor de secuenciacion de comandos en ActiveX.
Desventajas de Per1
L a gran desventaja de Perl es su efectividad. La ejecucion del codigo en Perl es
mucho mas lenta que la escrita con otros lenguajes de programacion como C.
E n el entorno de la Web, 10s script CGI que se escriben en Perl (y en otros lengua-
jes) se han de leer directamente del disco duro y cargar como un proceso nuevo
cada vez que se le llama. Las tecnologias como Active Server Pages y 10s servlet
en Java se pueden ejecutar en el mismo espacio de memoria que el servidor Web,
con lo que se acelerara notablemente la velocidad de ejecucion. En cualquier
caso, las ultimas versiones de Perl que se han desarrollado, como Perl para ISAPI
o Perl-Ex, han aumentado notablemente la efectividad.
Otro de 10s inconvenientes es que a Perl no se le considera u n lenguaje de pro-
gramacion elegante. Perl sacrifica la belleza de la programacion por la practica.
Funciona, aunque puede resultar bastante feo.
Per1 y CCI
Si solicita un archivo con la extension .htmla traves de un explorador Web, ob-
tendra u n documento estatico. Es decir, el fichero existe dentro de un directorio
Scripts e n Per1 51 1
Obtener Per1
Habra de instalar Perl en su ordenador. La mayoria de 10s servidores Web lo
tienen. Si tiene que hacerlo, podra obtener (gratuitamente) la ultima version de
Perl en ftp://ftp. rge.com/pub/languages/perl/ports/index. html.
Todo lo que tendra que hacer es clic sobre el vinculo correspondiente a su sis-
tema operativo. Si trabaja con WinNT/98/95, podra obtener la ultima version
de 10s ficheros ejecutables de Perl, y la inforrnacion correspondiente, de la direc-
cion http://www.activestate. com/pw32/. Si desea mas potencia y propiedades,
merece la pena que pruebe Active-Perl, una version Win32 de Perl, y que podra
encontrar en la direccion http://www.activestate.com/ActivePerV.
Ambos sitios Web proporcionan documentacion donde se explica como insta-
lar y configurar Perl. Per0 si trabaja con Windows, la cosa se simplifica aun mas.
512 ScriDts en Per1
Nota: Algunos servidores Web requieren que se ejecuten 10s script CGI con
la extension .cgi en lugar de hacerlo con . p l . No hay ningdn problema en
cambiar el nombre del archivo que nos ocupa por bag.cgi.
Vamos a ver cdmo desarrolla bag# las tres acciones. Cuando mire el codigo,
recuerde que es posible que no comprenda la sintaxis. Este libro no es de Perl.
Basta con que intente comprender qui ocurre de un paso a otro.
Ejemplo C . l . bag.pl
1 #!/usr/bin/perl
2
3 require (' cgi - 1ib .p 1 " ;
4
5 print "Content-type: text /html\n\n";
6
7 &Readparse (*in);
8
9 srand($$ ,.
time) ;
10 $filename = $in{'lname') . int(rand(999));
11
12 if (-e "$filename.txt"){
13 print "The order for $filename has already been placed.";
14 exit 0 ;
15 1
16
17 open (FILE,">$filename.txt " ) ;
18 select (FILE);
19 printInfo ( ) ;
20 close (FILE);
21 select (STDOUT
22 printInfo ( 1 ;
23
24 exit 0 :
25
26 sub printInfo
27 $clock = localtime ( ) ;
28
29 print <<CUSTOMER-INFO;
30 <PRE><FONT FACE=Tahoma SIZE=3>
31 <H2>Shopping Bag Order Confirmation Receipt</H2>
32
33 <B>$clock</B>
34 cB>Reference Code: $filename</B>
35
36
37 ___--____--__---__--
38 Customer Information
39
514 Scripts en Per1
#!/usr/bin/perl
require "cgi-1ib.pl";
&ReadParse(*in);
La primera linea es comun a todos 10s script CGI. Se encarga de indicar a1 ex-
plorador Web d6nde puede encontrar Perl. La ruta varia de una maquina a otra,
por lo que tendra que consultar con su administrador Web. Si trabaja con un
sistema Windows, podrh ignorarlo. La siguiente linea indica a Perl que ha de
incluir el c6digo que se encuentra en la biblioteca llamada cgi-Zib.pZ (nombre
estandar que se incluye con la mayoria de las instalaciones en Perl). Contiene el
codigo que se encargara de leer la informacion que se envia a travCs del formu-
lario HTML. Todo lo que hay que hacer es llamar a la subrutina adecuada de
Perl y el script leer&la informacion del formulario que se encuentra en las varia-
bles de la aplicacion.
La siguiente linea imprime una cabecera HTTP Dicha cabecera se encarga de
identificar el tipo MIME (Multipart Internet Mail Extension) y de comunicarselo
a continuaci6n a1 explorador, el cualdeterminara el tip0 de informacidn con la
que se va a encontrar. Sera text/htmZ. Entre otros tipos MIME tenemos image/gif
y text/plain.
JavaScript utiliza funciones y mktodos; Perl utiliza funciones, mCtodos y sub-
rutinas. La subrutina ReadParse ( ) de cgi-Zib.pZ lee 10s datos que ha introduci-
do el usuario en el formulario HTML y 10s coloca en un array asociativo llamado
%in.Los datos del formulario 10s veremos en breve. De momento basta con que
sepamos que 10s tenemos. Vamos a seguir avanzando.
srand($$ time);
A
$filename = $in{'lname') .
int(rand(999));
if (-e "$filename.txt") {
print "The order for $filename has already been placed.";
exit 0;
1
nombre del archivo unico. Para crear dicho nombre une el apellido del compra-
dor con u n numero aleatorio comprendido entre 0-999:
El apellido del usuario se ha obtenido de 10s datos del formulario. Como 10s da-
tos se han guardado en el array asociativo %in, todo lo que tendremos que hacer
sera acceder a1 elemento que contenga el apellido. A continuation podemos ver
la sintaxis:
$in{'lname'l
Si hace algo de memoria, recordara que Zname era uno de 10s campos que se
enviaban del formulario HTML. En Perl, lo mismo que sucede en JavaScript, las
referencias a 10s arrays asociativos se establecen a partir de su nombre. Por eso
$in{ ' lname ' 1 apunta a la informacion que ha introducido el usuario como
apellido (por ejemplo, "Garcia").
L a funcion de Perl rand ( ) genera aleatoriamente un numero con coma flotan-
te comprendido entre 0 y el numero que se le entrega, que es 999. Es decir, la fun-
cion de Perl i n t ( ) devuelve a1 numero entero el valor que rand ( ) le entregue.
Asi, $filename puede tener valores como Garcia23, Garcia997, Garcia102, etc.
Una vez que se ha determinado el nombre del archivo, Perl comprueba si dicho
archivo ya existe. Con este sistema se evita anular las ordenes que un compra-
dor haya hecho en el transcurso del dia. Por ejemplo, Garcia es un apellido muy
corriente. Si Javier Garcia y Ramon Garcia efectuan compras el mismo dia y por
alguna extraiia coincidencia, el generador de numeros aleatorios les asigna el
mismo numero entero, sus archivos serian exactamente iguales. El que compra-
se en segundo lugar borraria la informacion del primero:
i f (-e "$filename.txt") {
print "The order for $filename has already been placed.";
exit 0;
1
open(FILE, ">$filename.txt");
select (FILE);
printInfo0;
close(F1LE);
Scripts en Per1 51 7
sub printInfo0 {
$clock = localtime ( ) ;
print <<CUSTOMER-INFO;
<PRE><FONT FACE=Tahoma SIZE=3>
<H2>Shopping Bag Order Confirmation Receipt</H2>
<B>$clock</B>
<B>Reference Code: $filename</B>
CUSTOMER-INFO
print <<PAYMENT-INFO;
Payment Information
PAYMENT-INFO
$idx = 0 ;
$ idx++:
1
print <<TOTAL-INFO;
Subtotal: Sinput('subtota1')
Tax Total: SinputI'taxtotal')
Ship Total: Sinput('shiptota1')
Bag Total: SinputI'bagtotal')
tomo su propio nombre implica, printInfo ( ) imprime 10s datos del formu-
lario. Lo primer0 que hace es crear un sello basado en la fecha y en la hora, para
lo que usa la variable $clock, asignandola a la salida de la funcibn local t i m e ( ) .
Lo utilizaremos en un momento. En la lfnea 29 empieza la impresi6n. El c6digo
<<CUSTOMER-INFO identifica una cadena, que serA en realidad una serie de ca-
denas que se encuentran entre dos identificadores. CUSTOMER-INFO es el iden-
tificador. La utilizacion de las cadenas resulta muy util puesto que no hay que
preocuparse de 10s retornos de carro o de las comillas dobles. Estos caracteres se
utilizan de la misma forma que cualquier otro. De esta forma, Per1 siempre apun-
tar&a la informacion que se encuentre entre CUSTOMER-INFO y CUSTOMER-INFO,
que ser&:
<B>$clock</B>
<B>Reference Code: $filename</B>
------_-_--_-_--_---
Customer Information
ObsCrvese que no tenemos que unir varias cadenas que se extienden por varias
lineas. Basta con escribir. TambiCn conviene destacar las variables que se inter-
pretan. En otras palabras, $input { ' lname ' } no imprime $input { ' lname ' } ;
imprimira algo como "Garcia".
Si estudia el c6digo con cuidado, comprobara que lo primero que se imprime
son 10s datos postales correspondientes a1 comprador. Se encuentran en la in-
formaci6n de pago. Procede de ciertos campos del formulario, comofnarne, Znarne,
andcity. El usuario se habrii encargado de rellenarlos, por eso sabemos que esta-
ran alli.
iQuC sucede con la informacion del producto? El numero de productos puede
ser cualquiera. iC6mo sabra Perl la cantidad de productos que ha seleccionado
el usuario? Realmente no lo sabra. A continuacibn, las lineas 62-71 explican la
raz6n:
$idx = 0;
print <<TOTAL-INFO:
Subtotal : $input{'subtotal')
Tax Total: $input{ 'taxtotal')
Ship Total: Sinput('shiptota1')
Bag Total: $input{'bagtotal')
close (FILE);
select (STDOUT);
printInfo ( ) ;
exit 0:
Configurar el Script
Este script crea todos 10s archivos de texto de 10s pedidos de 10s productos y 10s
guarda en su mismo directorio. En otras palabras, 10s archivos de 10s pedidos se
guardaran en el mismo directorio donde se encuentre bag.pZ. No se puede utili-
zar ninguna estructura de directorios adicional. Cualquier carpeta con permi-
sos de ejecucion (necesarios para que el servidor pueda ejecutar el script) y de
escritura (para que el script pueda crear y escribir 10s archivos) sera valida.
Si desconoce el concept0 de permisos, sepa que controlan el acceso que tendran
10s usuarios a 10s distintos directorios y archivos. Por ejemplo, para recuperar 10s
archivos HTML, el directorio que 10s contenga necesitara contar con permisos
de lectura para acceder a su contenido. Para ejecutar 10s script (CGI o cualquier
ScriDts en Per1 521
otro), la carpeta necesitara contar con permisos de ejecucion. Para crear y mo-
dificar 10s archivos de dicho directorio, tambien necesitara permisos de escritu-
ra. El directorio que contiene bag.pZ necesitara permisos de escritura y ejecucion.
L a verdad es que parece sencillo, per0 tiene trampa.
Garantizar permisos de escritura y ejecucion a un directorio abre las puertas a
un par de riesgos relacionados con la seguridad. Si tiene u n servidor Web, sus
usuarios le pediran que guarde el script en un directorio que solamente tenga
permisos de ejecucion, como &-bin/ o Scripts/.y escriba 10s archivos en otro di-
rectorio que unicamente tenga permisos de lectura. En este caso, tendra que mo-
dificar el script para reflejar el nuevo directorio donde se guardaran 10s pedidos.
Bastara con incluir el nombre de la carpeta en la configuracion de la variable
$filename. Supongamos escribira 10s archivos en la carpeta orders/, que se en-
cuentra un nivel por encima del directorio donde se encuentra el script. Todo lo
que se ha de hacer es cambiar la linea 10:
por :
cgi -bin/
greet . p l
index.html
back. html
front.htm1
greetings/
images1
Nota: Algunos servidores Web requieren que se ejecuten 10s script CGI con
la extensibn .cgien vez de hacerlo con .pZ. No hay ningfin problema en cam-
biar el nombre del archivo.
3 require 'cgi-1ib.pl';
4
5 &ReadParse(*in);
6 $msg = $in('EntireMessage');
7 $fileID= $in('UniqueID'l;
8 $recip = $in(*Recipient');
9 $baseURL = $in{'BaseURL');
10
11 open(FILE, ">greetings/greet$fileID.html") 1 1 die "No can do:
$!";
12 select(F1LE);
13 print <<GREETING;
14 <HTML>
15 <HEAD>
16 <TITLE>Your Personal Cyber Greeting</TITLE>
11 < /HEAD>
18 <BODY>
19 Smsg
20 </BODY>
21 </HTML>
22 GREETING
23 close (FILE);
24 select(STD0UT);
25
26 print "Content-type: text/htrnl\n\n";
27
28 print <<RESPONSE;
524 Scripts en Per1
29
30 <HTML>
31 <HEAD>
32 <TITLE>Cyber Greeting Response</TITLEz
33 < /HEAD>
34 <BODY>
35 <TABLE WIDTH= 500" >
36 <TR>
31 <TD>
38 <H2>Congratulations!</H2>
39 You have successsfully created a Cyber Greeting for
40 <B>$recip</B>.All you have to do is send him or her an
41 e-mail to announce the greeting. Just push the button below,
42 and the e-mail will be on the way.
43 <CENTER>
44 <FORM NAME= SendEmai1 ENCTYPE=" text /p1ain
I' 'I I'
#!/usr/bin/perl
require 'cgi-1ib.pl';
&ReadParse(*in);
Scrbts en Per1 525
$msg = $in{'EntireMessage'l;
$fileID= $in{'UniqueID'l;
$recip = $in{'Recipient');
$baseURL = $in{'BaseURL');
print <<RESPONSE;
<HTML>
<HEAD>
Scripts en Per1 527
RESPONSE
miembros, 282
propiedades, 485
A, 41 Anchor, 434
ABSMIDDLE, 42 AND, 35
ACTION, 152 answer(), 76
action, 359 Anuncio directo, 269
addOpt0, 269 Anuncios, 412
adImages, 67 Aplicaci6n
administer.htm1, 79 de cliente, 3 7
ADSL, 28 rendimiento, 3 7
aFrame, 85 Applet, 434
age, 264 Appliances, 293
agregate, 185 Aptiva, 23
Agrupaciones, 68 Archivo
alert(), 39, 300 de cbdigo, 31
Algoritmo, 36 fuente, 38
Caesar, 359 Area, 436
Vinegere, 360 Arial, 41
ALIGN, 41 Arquitectura orientada a objetos, 26
ALINK, 93 Arrastrar y soltar, 371
Allaire, 27 Array, 38, 436
allconfirmation, 40 de elementos, 85
allImages, 141, 243 desordenar, 8 7
allowAny(),40, 49 dimensiones, 5 1
allowArray(), 48 manipular, 8 7
allstring, 40 multidimensional, 243
Alto nivel, 25 objeto de, 87
funciones, 485 ordenacih, 66
530 indice alfabktico
B, 43
C
background, 236 C + + , 26
backgroundIdx, 395 Cabecera, 27
Bag(),295 Cadena
bagTotal: 295 de b~squeda,35
Barra de desplazamiento, 108 delimitada, 44
Barra invertida, 44 sustitucih, 354
Base de datos, 35, 65 Caesar, 344
rendimiento, 66 caesarAlgorithm(),359
basechar, 356 Callsearch(), 151
baseUrl, 3 77 Cambio de efectividad, 30
Begin, 85 camelcap(), 116, 223
BGCOLOR, 41 Campos, 188
bkgImage, 246 Cancelacion de carga, 30
BLOCKQUOTE, 298 Capas, 112
BOA5501,291 captureDefaultProfile(), 189
BODY, 41, 121 Carga
Bolsa de la compra, 2 77 de trabajo, 35
agregar productos, 314 dinhmica, 142
crear, 295 Carro de la compra, 274
Boolean, 436 Cartel publicitario, 6 7
Booleano, 35 category, 291, 295
BORDER, 41 categoryset, 294, 296
hdice alfabetico 531
ceil, 91 Conexidn, 29
ceiling, 42 Configuracibn predeterminada, 46
CELLPADDING, 41,299 confirm(), 95, 256
CENTER, 41 Constructor, 32
CGI, 26, 509 Control, 153
ChangeAction(),385 Conversidn de cadenas, 329
changeBag(),303 convertstring(),40, 47
changeslide(), 121, 126 Cookies, 26, 231
charAt, 39 cookiesjs, 198
cheapcheck(), 305 copy, 113
CHECKBOX, 67,237,438 CopyArray, 39, 41
chickenput(),95 correct, 84
Cifrado, 339 Correo electrbnico, 3 71
correo, 369 Correo encriptado, 369
funcionamiento, 341 count, 175
Cipher(), 352 crear, 422
cipherkray, 353 administracibn, 145
cipherData, 362 funciones, 113
ciphertext, 342 cReset, 300
Cisco, 28 Cuadros anidados, 75
cleanText, 353 Cuerpo del texto, 55
clearInterval(), 129 curCLoc, 299
closeUpShop(),282 curGreet, 395
Cbdigo curPLoc, 299
archivo de, 3 1 currentMatch, 39
comtin, 30 currentRecord, 41
fuente, 44 currPfres, 249
generacibn, 44 curslide, 108, 127
ocultar, 31 Cyber Greetings, 3 71
piratear, 344
referencia a, 32
reutilizar, 3 1 data, 359
cOffset, 299 Date, 439
ColgFusion, 2 7 Dato formateado, 44
COLSPAN, 299 DD, 42
Combinaciones, 86 dDidLyr, 108
Compaq, 23 Declarar
compareElement, 40 funcibn, 32
Compatibilidad, 65 variable, 32
Compilacibn, 26 decPlace0, 303
Concatenar cadena, 44 Degradacibn, 30
532 hdice alfabetico
Deletecookie(),199 EMCA-262,27
Dell, 23 enableEffects0,204
delOpt(), 269 Encuesta, 99
description, 290 engHgt, 141
dHgtLyr, 108 enginelinkso, 145
DHTML, 25, 101,266 engWdh, 141
capas, 108 Enlace, 36
dhtml.js, 202 Entero, 86
diaply(), 213 EntireMessage, 41 0
Diapositivas, 101 entry, 39
aleatorias, 131 Error, 26
animar, 131 de sintaxis, 127
elementos, 122 Esc, 44
Dimensiones, 5 1 escape(),152
Direccibn IF: 111 Esquema
display(), 308 de aplicacibn, 73
DIV, 114 deflujo, 74
dive.html,234,258 Estado del cliente, 296
divide, 41 Estrategia
docObj, 39 de inversibn, 243
Document, 443 de programacibn, 2 7
document Estratificacibn, 26
bgcolor, 76 eval(), 125
close(), 77 EVEN, 68
fgcolor, 76 Event, 445
open0, 77 event .js
write(), 60 Examen online, 69
writelno, 60 explain(), 94
Documento Exploradores cruzados, 30
administracibn, 284
cargar, 389 F
descripcibn, 43
Imagen, 27 FACE, 41
localizador de, 36 face, 236
titulo, 43 Factura, 328
Dow Jones, 236 false, 40
DT, 42 Familia de fuentes, 243
Fase de compilacibn, 26
E Fileupload, 44 7
findings, 40
Editor de textos, 31 Flash, 25
else, 39 Flexibilidad, 85
indice alfabktico ~~
533
Lista N
de seleccibn, 325
desplegable, 277 NAME, 42
Liveconnect, 69 NASDAQ, 236
Llave nav.htm1, 39, 64
publica, 342 navbaro, 214
simitrica, 342 navbar.js
Localizador, 36 Navegacih, 112
low(), 194 Navigator, 463
lyrCount, 146 Netscape, 464
Netscape Navigator, 23
new, 39
newsName, 243
Macintosh, 23 nextBackground(), 399
Macromedia, 25 nextIcons(),400
mailto, 369 nextQ, 84
makeObj0, 218 nextRound0, 8 7
makepatho, 141, 249 NN, 108
makeproducts, 2 93 noMatch(),41, 54
manager.htm1, 283, 298 Nombre
Maquina local, 29 asociado, 115
Maquina virtual, 2 7 convenio para, 115, 264
Marco NOSHADE, 41
comunicaci6n, 396 NOT, 68
definicih, 396 NOT LIKE, 154
Marketing, 269 null, 260
Math, 87, 460 Number, 464
Memoria, 35 numberFormat, 300, 302
Mensaje de correo, 27 numbers.js, 2 16
menuConstraint, 108, 117
menuManager-0, 124 0
menuStr, 117
Mktodo, 35 Object, 465
Microsoft Internet Explorer, 23 objects.js, 218
MIDDLE, 42 Objeto
mimeType, 76, 182,462 agregar propiedades, 3 16
Modularidad, 46 asignar mktodo, 352
Mostrar informacibn, 424 definido por el usuario, 32
motionListener(),389 herencia de, 363
Motor de busqueda, 35, 133 imagen, 26
msgStr, 407 implementacih, 78
multi.htm1, 136 objProfile0, 2 18
536 indice alfabktico
Radio, 468
rank, 84, 91 safecharso, 238
rankIdx, 93 scientific, 115
rawNumStr0, 302 Screen, 473
rawText, 353 screen, 110
RDSI, 28 SCRIPT, 27, 260
538 hdice alfabetico
Y
Yahoo!, 154
WDDX, 27
while, 39
WIDTH, 41
Z
Window, 481 zIdx, 108
Soporte Tecnico de Anaya Multimedia
Si tiene algun problema relacionado con el contenido de nues-
tras publicaciones, o con el material suministrado en las mis-
mas, por favor comuniquelo a nuestro Departamento de
Soporte Tecnico a traves de alguno de estos medios:
0 CORREO
ELECTRONICOa la direccion, a-multimedia8anaya.es.