Bé, aquesta és l'última pràctica del curs i segur que ens hem deixat molts aspectes sobre DHTML i JavaScript sense comentar o aprofundir. Entendre i aprendre un llenguatge no és el mateix que dominar totes les seves possibilitats. Això requereix molt de temps, potser anys, fins i tot hi ha qui pensa que no s'acaba mai.

Sigui com sigui, tenim la base suficient per donar un gir espectacular a les nostres pàgines i continuar aprenent. Ara, el que toca és ser pràctics i veure com podem rendibilitzar al màxim el que sabem fer i el que anirem incorporant. Tots els exemples d'aquesta pràctica són candidats a formar part de moltes pàgines.

  Conceptes JavaScript en aquest capítol
Propietat prototype : permet afegir, esborrar o modificar propietats i mètodes d'un objecte.
Comportament onerror : determina què s'ha de fer si es produeixen errades.
Mètode sidebar.addPanel() : afegir una adreça als preferits (Netscape 6+, Mozilla)
Mètode external.AddFavorite() : el mateix, però amb Internet Explorer.

  1.- Enllaçar arxius externs
Si volem utilitzar bocins de codi en diversos llocs, el més pràctic és que els guardem en arxius i els enllacem a les pàgines. Això, que fem per força amb les imatges, els sons, els vídeos o el Flash - tots són bits - ho podem fer també amb arxius de text.

Un script contingut en un arxiu s'enllaça utilitzant l'etiqueta <script> amb el modificador src assignat a l'arxiu. També hi podem afegir el tipus o el llenguatge utilitzat:

  <script  language="JavaScript"  type="text/javascript"  src="arxiu.js"></script>

Si l'arxiu enllaçat només conté funcions - sense codi que s'hagi d'executar mentre es llegeix -, podem forçar que es vagi carregant "de fons", mentre es va llegint la pàgina, utilitzant el modificador defer. Així accelerem la càrrega de la pàgina.

  <script defer language="JavaScript"  type="text/javascript"  src="arxiu.js"></script>

Per enllaçar un arxiu de definició d'estils utilitzem l'etiqueta <link> amb l'arxiu assignat a href. A més, definim la relació, el tipus i el medi:

  <link  rel="stylesheet"  href="pantalla.css"  media="screen"  type="text/css">

L'etiqueta <link> pot tenir altres utilitats i altres modificadors. Els navegadors no en fan ús, però no es descarta que els utilitzin en futures versions. Alguns cercadors, en canvi, sí que els poden utilitzar per crear una mena de "mapa del lloc". Alguns d'aquests modificadors són: target (finestra destí), hreflang (idioma), charset (conjunt de caràcters), ...

El modificador "rel" pot tenir, al seu torn, diversos valors: start, prev, next, help, glossary, contents, copyright, fontdef, alternate, ... De tots els possibles, els navegadors utilitzen l'últim, alternate, per especificar un full d'estils alternatiu. Amb això i alguns scripts podríem, per exemple, fer pàgines personalitzades. Aquest és un tema "d'última fornada", massa extens per ser tractat aquí. Això sí, sabem que hi és i, a partir d'ara, el trobarem cada cop en més pàgines.

Com a curiositat, i també com a component útil, tenim un arxiu, styleswitcher.js, que proporciona tota la funcionalitat per utilitzar fulls d'estils alternatius. El seu autor és un jove britànic, Paul Sowden. Més informació a la seva web: http://idontsmoke.co.uk

 
2.- Llibreries
Alguns llenguatges de programació avançats utilitzen llibreries. Es tracta de col·leccions de funcions organitzades que s'enllacen de forma dinàmica - només les que es necessiten - amb el codi que escrivim, en el moment de la compilació, per generar els executables.

JavaScript no es compila i no disposa de llibreries. Però podem crear, organitzar i guardar arxius amb les funcions més comunes, de manera que, quan les necessitem, només ens calgui enllaçar-les amb el font, o "copiar i enganxar" a les nostres pàgines.

De fet, la creació de llibreries no està limitada al JavaScript. Podem fer-ne també de fulls d'estils, d'estructures HTML o, com vam fer al primer mòdul, d'estructures de carpetes. Tot allò que puguem tornar a necessitar, ho podem guardar i considerar una llibreria.

Com que aquestes col·leccions, amb el temps, poden anar creixent, és fonamental tenir una bona organització i molta claredat. Això sí, si ens dediquem a inserir comentaris al propi codi, ocuparem un espai i un temps de càrrega innecessaris. És preferible acompanyar cada carpeta amb un arxiu de text que inclogui explicacions sobre el seu contingut.

Pel que fa als scripts, els podem escriure com vulguem, provar, rectificar, ... Un cop acabats - hem d'estar segurs que ja no els modificarem més -, hauríem de fer que ocupin el mínim espai. Per això, guardem la funció en el seu format original (amb comentaris, si cal) i en fem una còpia. Podem anomenar els originals, per exemple, "xxxx.ori" i les còpies "xxxx.js".

A la còpia, substituïm els noms de les variables, els deixem només amb una lletra, eliminem els espais innecessaris i canviem els salts de línia pel signe ";" (punt i coma). Queda com una botifarra de signes, difícil de llegir. És el més semblant a una compilació.

Com a exemple, fem una funció per formatar els milers. Rebrà un número (amb o sense decimals), el convertirà en cadena, separarà enters i decimals, partirà els enters en grups de tres - començant per la cua - i ens tornarà la cadena amb els milers separats per punts i els decimals per una coma.

Primer hem escrit la funció amb variables normals. Un cop provada, les hem canviades per variables d'una lletra (ho podem veure al codi) i, finalment, hem tret els espais. La funció ha passat dels 523 bytes inicials als 232 finals, és a dir un 45% del que ocupava. A més, el codi resultant és més difícil d'interpretar i, en conseqüència, té menys interès per a la pirateria.

Com hem escrit la funció (amb variables d'una lletra):
<script language="javascript">
function formatMil(x) {
  x += ''
  var a = x.split( '.' )
  var n = a[0]
  var l = n.length
  var c= ''
  if (parseInt(n) + '' == n) {
    while (l>3) {
      c = "." + n.substr( l-3, 3 ) + c
      n = n.substr( 0, l-3 )
      l = n.length
    }
    if (n.length>0) c = n + c
    if (x.indexOf( '.' )>0) c += ',' + a[1]
  }
  return c
}
</script>

Funció preparada per formar part d'una llibreria:
function formatMil(x){x+='';var a=x.split('.');var n=a[0];var l=n.length;var c='';
if(parseInt(n)+''==n){while(l>3){c="."+n.substr(l-3,3)+c;n=n.substr(0,l-3);l=n.length}
if(n.length>0)c=n+c;if(x.indexOf('.')>0)c+=','+a[1]}return c}

 
3.- Noves funcionalitats per a vells objectes
Els llenguatges orientats a objectes - Java, C++ - basen la seva herència en classes. Els objectes JavaScript, en canvi, utilitzen l'herència basada en prototips. Els constructors creen instàncies basades en les propietats i mètodes definits al prototip dels objectes.

Tots els objectes tenen la propietat prototype, que permet afegir, esborrar o modificar propietats i mètodes de l'objecte original, de manera que les noves instàncies els heretin. Això ens permet, per exemple, atorgar als objectes noves funcionalitats.

Afegirem quatre mètodes nous a les cadenes (objecte String). Són típics d'altres llenguatges, de manera que molts programadors hi estan acostumats. Els dos primers, left(n) i right(n), retornen un bocí de la cadena, per l'esquerra o per la dreta, amb la longitud que indiquem. Utilitzen el mètode substr() (també podem escriure "substring"), que ja coneixem.

El següent mètode, trim(), elimina els espais en blanc que hi pugui haver a l'inici i/o la fi d'una cadena, utilitzant una expressió regular. L'últim mètode, rep(n), retorna una cadena a base de repetir els caràcters de què està formada, el número de vegades que especifiquem.

De passada, veurem una nova manera de declarar mètodes i funcions, recomanada pel W3C, l'organisme que regula els estàndards d'Internet:

  Objecte.prototype.metode = function( paràmetres ) { ... instruccions ... }

Aquests quatre mètodes funcionen. Recordem, però, que si els volem incorporar en forma de llibreria, hauríem d'eliminar abans els espais que sobren.

<script language="javascript">
String.prototype.left = function(n) {
  return this.substr( 0, n )
}
String.prototype.right = function(n) {
  return this.substr( this.length - n, n )
}
String.prototype.trim = function() {
  return this.replace( /^\s*(\b.*\b|)\s*$/, '$1')
}
String.prototype.rep = function(n) {
  var s = '', t = this.toString()
  while (--n >= 0) s += t
  return s
}
</script>
 
4.- Control d'errades
Amb les errades passa una cosa curiosa: sempre n'hi ha. Quan es mostra el missatge que proporciona el navegador, fa mal efecte. En canvi, si el missatge és personalitzat, la nostra reputació com a programadors millora. Doncs, bé; com que no sempre podem evitar-les, almenys, aprofitem-les.

L'exemple següent mostra un mecanisme per informar sobre les errades, molt simple. L'ideal seria incloure-hi un formulari i un botó, amb el prec que es premi per informar-nos sobre les incidències. Això sí que és donar-li la volta a la truita!

Per començar, desviem les errades cap a una funció: window.onerror = eAfegir. A continuació declarem tres Arrays que contindran, respectivament, el missatge, l'adreça i la línia de l'errada. El navegador passa aquests paràmetres a la funció de forma automàtica.

La funció receptora, senzillament, afegirà elements a cada Array amb els valors rebuts. Per això s'utilitza la propietat length, que és l'índex de l'últim element. La funció retorna "true" i, com ja sabem, s'evita que s'engegui el comportament per defecte.

Farem encara una altra funció que mostri l'informe. Crearem una finestra on escriurem, amb l'ajut d'un bucle, els valors dels tres Arrays. Finalment, tanquem el document de la finestra. Això és el mínim. Com ja hem dit, aquí s'hauria de donar bona impressió i demanar a l'usuari que ens informi sobre les errades. Podem aprofitar per incloure-hi altres informacions, que ja hem vist als exemples del mòdul anterior (mòdul 7, pràctica 3, exemples 1 i 2).

<script language="javascript">
window.onerror = eAfegir
aMsg = new Array()
aUrl = new Array()
aLin = new Array()
function eAfegir(msg, url, lno) {
  aMsg[aMsg.length] = msg
  aUrl[aUrl.length] = url
  aLin[aLin.length] = lno
  return true
}
function eMostrar() {
  winError=window.open('','error','scrollbars=yes')
  with ( winError.document ) {
    writeln('<b>Informe d\'errades:</b><br><br>')
    for (var i=0; i < aMsg.length; i++) {
      writeln('<b>Arxiu:</b> ' + aUrl[i] + '<br>')
      writeln('<b>Línia:</b> ' + aLin[i] + '<br>')
      writeln('<b>Error:</b> ' + aMsg[i] + '<br><br>')
    }
    close()
  }
}
</script>
</head>

<body ...>
<a href="javascript:
eMostrar()">Informe d'errades</a>
...
 
5.- Afegir la pàgina als marcadors preferits
De vegades cal fer una feina que afecta propietats específiques del navegador i que tenen poc a veure amb la pàgina. És el cas de la funció que ara presentem. Com que cada navegador utilitza funcions diferents (fins i tot, nom diferents) per als "Favoritos", haurem de comprovar primer l'existència d'uns objectes determinats i, després, escriure les funcions adients.

A partir de la versió 6 de Netscape s'utilitza l'objecte window.sidebar i el mètode addPanel(). Internet Explorer fa servir el mètode external.AddFavorite(). Finalment, les versions de Netscape anteriors a la 6 no ofereixen cap possibilitat, l'únic que podem fer és presentar un missatge.

<script language="javascript">
function afegirFav() {
  var url = location.href
  var nom = document.title
  if ( window.sidebar && window.sidebar.addPanel ) {
    window.sidebar.addPanel( nom, url, '' )
  }
  else {
    if ( document.all ) window.external.AddFavorite( url, nom)
    else alert( 'Premeu Control + D per afegir la pàgina als marcadors' )
  }
}
</script>
</head>

<body ...>
<a href="javascript:
afegirFav()">Afegir als marcadors</a>
...