El DOM i el model d'events que manegen els diferents navegadors i versions són diferents. Això implica que els scripts han de tenir en compte aquestes diferències, si volem que funcionin en tots dos.

Els navegadors actuals permeten modificar gairebé tots els elements de la pàgina quan ja ha estat descarregada. Netscape 4.7, en canvi, és més restrictiu, com ho és també quan es tracta de fulls d'estils i, fins i tot, d'algunes etiquetes HTML.

No és estrany que Internet Explorer sigui el preferit a nivell mundial (75% d'usuaris, i creixent). Això, però, no vol dir que tothom l'utilitzi. El seu lligam amb Windows fa que els usuaris d'altres Sistemes hagin d'utilitzar Netscape o Mozilla, i no els podem pas oblidar. L'ideal és fer pàgines amb la màxima compatibilitat entre tots els exploradors.

En aquesta pràctica aprendrem a detectar el navegador i dirigir el flux de la pàgina en un o altre sentit , de manera que puguem superar, en la mesura que sigui possible, les greus incompatibilitats que els separen.

  Conceptes JavaScript en aquest capítol
Objecte navigator : el navegador.
Propietat appName : mostra el nom del navegador.
Propietat appVersion : versió del navegador, en format text.
Propietat platform : la "plataforma" (sistema operatiu) del client.
Propietat userAgent : capçalera HTTP que informa sobre el navegador.
Mètode javaEnabled() : comprova si es poden executar applets de Java.
Objecte document.all : tots els elements de l'objecte document. Només Internet Explorer.
Objecte document.layers : Array que conté una entrada per a cada capa. Només Netscape.

  1.- Navegador i versió
Hi ha molts navegadors i versions. Com que aquests programes són els responsables d'interpretar la pàgina i, entre ells, hi ha diferències notables, serà difícil que tot el que escrivim funcioni de la mateixa manera en totes les ocasions. De vegades haurem d'escriure porcions de codi o, fins i tot, pàgines senceres, específiques per a cada navegador.

Sortosament, JavaScript reconeix el navegador. Podem consultar les propietats de l'objecte window.navigator per saber amb quin estem tractant. Per veure-les, obrim qualsevol pàgina amb l'inspector d'objectes, escrivim "navigator" al quadre "Obj" i fem clic en el botó "Mostrar".

En aquest exemple només comprovarem dues propietats: el nom del navegador (appName) i la versió (appVersion). Aquesta última és un text i, en alguna ocasió, necessitarem discriminar a partir del número pelat. Cap problema, ho passem per la funció parseInt().

El número de versió fa referència al nucli del navegador, de manera que si, per exemple, tenim Internet Explorer 6, la versió és 4, perquè les versions 4, 5 i 6 d'aquest navegador es basen en el mateix nucli, i aquest és el que interessa per saber com es comportaran les pàgines. Alguna vegada, però, necessitarem l'altre, perquè hi ha diferències importants.

<script language="javascript">
<!--

var navegador = window.navigator.appName;
var versio = window.navigator.appVersion;
document.writeln( 'Navegador: ' + navegador + '<br>Versió: ' + versió );
document.writeln( '<br>Versió del nucli: ' + parseInt( versió ) );
// -->
</script>
 
2.- Més informació
L'objecte navigator també proporciona altres informacions (té altres propietats) que, curiosament, depenen del navegador que utilitzem. Aquí sí, Netscape en té més, i algunes força interessants, com ara mimeTypes i plugins, dos Arrays que informen, respectivament, sobre els tipus d'arxius reconeguts pel sistema i els plug-ins que té instal·lats.

Pel que fa a les propietats "compatibles", que reconeixen tots dos navegadors, n'hi ha tres que en algun moment podem necessitar saber: plataforma, agent d'usuari i java activat.

Plataforma (platform) és el tipus de sistema operatiu que utilitza l'ordinador client. Els valors possibles són Min32, Win16, Mac68k, MacPPC i Unix. Naturalment, com que els sistemes i els navegadors evolucionen, aquest valors poden quedar obsolets en quatre dies.

I què vol dir "Agent d'usuari" (userAgent)? Quan el client envia una petició al servidor a través del protocol HTTP, s'acompanya d'algunes dades, és el que s'anomena "capçaleres HTTP". Aquesta, en concret, és la informació completa sobre el navegador que utilitza el client.

L'objecte navigator té un mètode que comprova si el navegador pot executar applets de java (javaEnabled()), molt útil abans de carregar-ne, doncs ho podem detectar i, en cas que no estigui activat, oferir una via alternativa.

En aquest exemple utilitzem una variable (javaOk) i l'operador condicional ternari (?) per tal de crear una frase a bocins: "Java " + (si Java activat, res, si no, "des") + "activat".

<script language="javascript">
<!--

var javaOk = navigator.javaEnabled();
document.writeln( 'Plataforma: ' + navigator.platform + '<br>' );
document.writeln( 'Agent d\'usuari: ' + navigator.userAgent + '<br>' );
document.writeln( 'Java ' + ( (javaOk) ? '': 'des' ) + 'activat' );
// -->
</script>
 
3.- Carregar arxius diferents
Quan no hi ha manera de fer compatibles els estils i/o les funcions entre tots dos navegadors, podem optar per mantenir arxius separats i utilitzar els uns o els altres. En aquest exemple s'enllaça un full d'estils i un script.

Si el navegador llegeix </script>, interpretarà que s'ha acabat javascript i ha tornat a HTML. Per tal d'evitar-ho utilitzem el truc, - barroer, però efectiu - d'escriure-ho a bocinets.

        document.writeln( '</s" + "cript>');

Abans de decidir una solució com aquesta cal valorar, d'una banda, el fet de mantenir arxius separats i, de l'altra, el "pes" de carregar un únic arxiu amb tots els condicionals. En el primer cas, tenim l'inconvenient que, si fem modificacions, haurem de revisar dos arxius. En el segon ens estalviem aquesta feina, però la càrrega de la pàgina pot resultar més lenta.

<script language="javascript">
<!--

if ( navigator.appName.indexOf( "Microsoft" ) >= 0 ) {
  document.writeln( '<link rel="stylesheet" href="msie.css" type="text/css">' );
  document.write( '<script language="javascript" src="msie.js">' );
  document.writeln( '</s'+ 'cript>');
}
else {
  document.writeln( '<link rel="stylesheet" href="netscape.css" type="text/css">' );
  document.write( '<script language="javascript" src="netscape.js">' );
  document.writeln( '</s" + "cript>');
}
// -->
</script>
 
4.- Fes-ho, ... si ho pots fer
De vegades interessa saber si el navegador té una propietat específica o pot executar un mètode concret. Per exemple, quan tractem amb capes, Explorer i Netscape 4.7, a més de ser incompatibles, no les tracten de la mateixa manera en totes les versions.

Abans d'intentar usar aquestes propietats o mètodes cal, doncs, comprovar què es pot fer. Si coneixem totes les peculiaritats de les diverses versions dels navegadors podrem usar la tècnica de l'exemple anterior. Gairebé sempre, però, resulta més pràctic, curt i segur comprovar directament la disponibilitat d'allò que volem utilitzar.

Internet Explorer i els altres navegadors actuals tenen document.all, un Array amb tots els components de la pàgina. Si un element no pertany a cap col·lecció (p.ex. no és cap imatge, formulari, marc, ... ) però li hem posat un identificador, el tindrem a l'abast a document.all[ identificador ]..

Netscape 4.7, en canvi, té la col·lecció document.layers. Es tracta d'un Array amb totes les capes definides. Els seus elements no són accessibles directament (són objectes), però sí que ho són les propietats, p.ex. document.layers[ identificador ].bgColor.

La versió 2 del DOM, implementada a Netscape 6, a Mozilla i, qui sap, potser un futur estàndard, aporta el mètode document.getElementById, que permet referir-se als objectes pel seu identificador. En aquest exemple, però, no l'utilitzarem.

Aquí volem utilitzar aquesta diferència per dirigir el flux de la pàgina, segons el navegador. Si té document.all, és l'Explorer, i si té document.layers, és Netscape 4.0 o superior. Si ho hem de comprovar diverses vegades és millor que ho guardem en una variable de tipus lògic:

  var ns = document.layers;
  if ( ns )
     ... instruccions Netscape 4.7 ...
  else          ... instruccions iExplorer ...

L'exemple crea "rollovers" de text, enllaços que, quan passa el ratolí, canvien el seu color de fons. Farem els vincles sobre contenidors (span), amb identificador únic i posició relativa.

Assignarem els events onMouseOver i onMouseOut a la funció "pinta", de manera que, quan passi el ratolí, s'activi un color de fons i, quan surti, es desactivi. A més, utilitzarem colors diferents i funcionarà amb Netscape 4.7, tot un luxe i una alternativa al a:hover de css.

La funció rebrà dos paràmetres: l'identificador i el color. Si s'utilitza amb Netscape 4.7, primer comprovarà que el color no estigui buit i, si és així, li assignarà el valor null. A continuació modificarà el color de fons del contenidor, document.layers[idSpan].bgColor. Si utilitzem Éxplorer, la sintaxi és diferent: document.all[idSpan].style.background.

Les propietats all i layers només són un petit exemple del que es pot fer. Si observem qualsevol pàgina amb l'inspector d'objectes, amb tots dos navegadors, veurem que tenen propietats ben diferents. Així podem saber què funcionarà i, alhora, com els podem distingir.

A la pràctica següent veurem més detalls sobre identificadors, posicions... .Tornen els estils!

<script language="javascript">
<!--

var ns = document.layers;
function pinta( idSpan, clr ) {
  if (ns){
    if (clr=='') clr = null;
    document.layers[idSpan].bgColor = clr;
  }
  else document.all[idSpan].style.background = clr;
}
// -->
</script>
</head>

<body><h3>
<a href="pagina1.htm"
onMouseOver="
pinta( 'lnk1', '#CCEEBB' )" onMouseOut="pinta( 'lnk1', '' )">
<span id='lnk1' style="position:relative">Enllaç 1</span></a>
<a href="pagina2.htm"
onMouseOver="
pinta( 'lnk2', '#FFDDBB' )" onMouseOut="pinta( 'lnk2', '' )">
<span id='lnk2' style="position:relative">Enllaç 2</span></a>
<a href="pagina3.htm"
onMouseOver="
pinta( 'lnk3', '#CCDDFF' )" onMouseOut="pinta( 'lnk3', '' )">
<span id='lnk3' style="position:relative">Enllaç 3</span></a></h3>
...