Les behaviors, mais qu'est-ce donc ?

Table des Matières

Prérequis

Pour pouvoir apprécier pleinement cette page il faut quelques prérequis. Le premier est de regarder la page sous Internet Explorer 5 (ou plus). Même si les autres navigateurs peuvent lire la page les behaviors sont spécifiques à Microsoft et donc l'exemple ne peut-être visualisé que sous cet environnement. Ensuite il faut quelques connaissances. Le HTML, les feuilles de style et le javascript sont un minimum à connaître pour apprécier complètement l'article (du moins dans les détails techniques).

Aperçu

Les behaviors ont été introduits par Microsoft dans la version 5 d'Internet Explorer. Comme d'habitude c'est une proposition pour le W3C, doux euphémisme pour dire que c'est une extension propriétaire. Le but des behaviors est de séparer encore plus le contenu de la présentation. A ce titre c'est donc une extension des feuilles de style... et d'ailleurs ça se positionne comme une feuille de style.

Mais encore... ça fait quoi ?

Il était une fois le javascript... c'est en gros ce que se dit tout développeur de pages web qui désire faire des effets un peu sympa dans sa page. Le seul problème c'est que pour écrire du javascript un peu générique il faut se lever de bonne heure. Et pour le réexploiter bof. On peut bien entendu mettre son code dans un fichier séparé mais la réutilisabilité est limitée.

L'autre problème de Javascript c'est que même si on a fait un joli script permettant de modifier quelque chose en dynamique, il faut tout de même l'appeler. Par exemple imaginons un tableau dont on désire modifier la couleur de fond des lignes quand la souris passe dedans. Ca veut dire que pour chaque ligne il faut écrire un gestionnaire onMouseOver et un gestionnaire onMouseOut. Sous IE ça pourrait donner ça :

<TABLE>
<TR onMouseOver="this.bgColor='#CCCCCC';" onMouseOut="this.bgColor='white';">
<td>Colonne 1</td>
<td>Colonne 2</td>
</TR>
<TR onMouseOver="this.bgColor='#CCCCCC';" onMouseOut="this.bgColor='white';">
<td>Colonne 1 ligne 2</td>
<td>Colonne 2 ligne 2</td>
</TR>
[...]
</TABLE>

Bref on se rend compte que le comportement de la ligne est générique et on aimerait donc le factoriser. Ca tombe bien, c'est à ça que sert un behavior (dont la traduction en français est comportement... tient donc !).

Comment ça fonctionne ?

En gros on fait un fichier .htc dans lequel on va écrire notre behavior de façon générique. Comme le but c'est de gérer l'élément à la volée, le mot clé this est associé à l'élément sur lequel est attaché le behavior. On peut alors jouer avec des this.style voir même des this.className (attention tout de même à conserver un behavior sur la nouvelle classe).

Ce behavior est ensuite attaché à n'importe quel élément de la page HTML comme on attacherait un style. On a donc plusieurs options :

  • le mettre dans une classe de la feuille de style
  • utiliser le mot clé STYLE sur l'élément à modifier

Exemple de définition de style :

<STYLE TYPE="text/css"><!--
.beh { behavior: url('monbehavior.htc'); }
//-->
</STYLE>

On peut bien entendu mettre d'autre choses sur la classe comme color et autres... mais ce n'est pas un article sur les feuilles de style que je suis en train d'écrire ! ;-)) La classe s'utilise très facilement de par la suite. Pour revenir sur le tableau :

<TABLE>

<TR CLASS="beh">
<td>Colonne 1</td>
<td>Colonne 2</td>
</TR>
<TR CLASS="beh">
<td>Colonne 1 ligne 2</td>
<td>Colonne 2 ligne 2</td>
</TR>
[...]
</TABLE>

Et je met quoi dans le .htc ?

Le fichier .htc est en fait un fichier contenant deux parties distinctes : une partie déclarative et une partie script. La partie déclarative explique ce que fait le behavior et comment il s'insère dans la page tandis que la partie script implémente le comportement. C'est comme les packages en PL/SQL, les unités en Pascal ou les fichier .h / .cpp en C (sauf que pour les .htc tout est dans le même fichier).

Partie déclarative

C'est dans cette zone que l'on déclare quels événements on veut intercepter et que l'on déclare de nouveaux attributs. En effet les behaviors permettent d'enrichir les balises standards pour passer des paramètres au behavior, le rendant ainsi plus générique (mais rien n'empêche d'avoir des valeurs par défaut). Il est même possible de déclarer tout cela dynamiquement via un lot de fonctions spécialisées.

Le plus simple c'est de prendre un exemple. Voici donc la partie déclarative d'un fichier .htc assez simple.

<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="menuOver()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="menuOut()" />
<PUBLIC:PROPERTY INTERNALNAME="hiliteColor" NAME="MOBGCOLOR" />

Comme vous pouvez le constater, la syntaxe est celle d'un fichier XML (comme l'indique le />). L'exemple ci-dessus est relativement simple. Les deux premières lignes indiquent que l'on veut gérer les événements onmouseover et onmouseout via les fonctions menuOver() et menuOut() qui sont alors automatiquement appelée lorsque l'événement source est déclenché. La dernière ligne permet de créer un nouvel attribut de balise qui s'appelle MOBGCOLOR. La valeur de cet attribut est stockée dans la variable hiliteColor. Il est possible de pré-initialiser cette variable dans la section script. Dans ce cas si l'attribut est présent c'est sa valeur qui compte, sinon c'est la valeur par défaut.

Le script

A chaque événement intercepté on a affecté une fonction que l'on peut écrire en JScript, JavaScript (il y a de subtiles différences), VBScript, etc. Personnellement j'utilise le JScript (implémentation enrichie de Javascript et d'ECMAScript) car les behavior sont déjà du pur spécifique IE... alors pourquoi se priver de fonctionnalités supplémentaires ?!

Comme pour tous les scripts, cette section commence par une balise <SCRIPT> et se termine par </SCRIPT>. Il faut spécifier le langage dans la balise script pour éviter les surprises. Ainsi peut avoir :

<SCRIPT LANGUAGE="JScript">

// On peut avoir besoin de variables globales, alors hop on en met. Elles
// seront de toutes façons locales au behavior (sauf si précisé autrement ;-)).
var toto;

function mouseOver()
{
// Ici plein de choses à faire lorsque la souris passe sur
// un élément actif.
}

function mouseOut()
{
// Rétablir l'état précédent
}
</SCRIPT>

Vous remarquerez qu'il n'est pas nécessaire de protéger le script par les balises habituelle <!-- et --> car le script est inclus dans un fichier séparé. Il n'y a donc pas de risques de mauvaise interprétation par un vieux navigateur qui de toutes façons ne lira pas la feuille de style (protégée par commentaires) ni par les navigateurs plus récents incompatibles avec les behaviors qui, croisant un mot clé inconnu, ignorera la déclaration.

Exemple complet

Au début de cet article j'avais pris comme exemple un tableau dont les lignes réagissent à la présence de la souris en changeant leur couleur de fond. Voici comment l'implémenter avec les behaviors de façon assez générique :

<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="Hilite()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="Restore()" />
<PUBLIC:PROPERTY INTERNALNAME="hiliteColor" NAME="MOBGCOLOR" />

<SCRIPT LANGUAGE="JScript">

var normalColor;
var hiliteColor = "#CCCCCC";

function Hilite()
{
normalColor = style.backgroundColor;
runtimeStyle.backgroundColor = hiliteColor;
}

function Restore()
{
runtimeStyle.backgroundColor = normalColor;
}
</SCRIPT>

Vous remarquerez l'utilisation d'un attribut personnalisé ayant une valeur par défaut via l'initialisation du script. Il est cependant possible de procéder autrement en détournant l'événement ondocumentready (qui est déclenché lorsque le document parent est chargé) pour initialiser dynamiquement la variable et attacher les événements (ce qui évite leur utilisation tant que le document source n'est pas totalement chargé). Je trouve néanmoins ma solution plus lisible car il n'est plus alors utile de lire la fonction init() pour savoir quels événements sont gérés par le behavior. Voici un fichier HTML exemple :

<HTML>

<HEAD>
<TITLE>Exemple de behavior</TITLE>
<STYLE type="text/css"><!--
// On suppose que l'exemple précédent est stocké dans le même répertoire que
// ce fichier et sous le nom test.htc.
exemple { behavior: url('test.htc'); }
//-->
</STYLE>
</HEAD>
<BODY>
<TABLE WIDTH="100%" CELLPADDING="2" CELLSPACING="1">
<TR CLASS="exemple">
<TD>Attribut personnalisé</TD>
<TD>inexistant</TD>
</TR>
<TR CLASS="exemple" MOBGCOLOR="white">
<TD>Attribut personnalisé</TD>
<TD>white</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Cet exemple donne :

Attribut personnalisé inexistant
Attribut personnalisé white

C'est génial... mais...

Et oui, malheureusement, il y a un mais. Et de taille en plus. Le premier concerne l'utilisation de ces behaviors sur internet. Outre le fait que c'est spécifique à internet explorer il y a aussi la façon dont c'est déclaré. Si vous avez bien fait attention, on utilise la commande url soit dans le style, soit dans la classe. Or pour chaque instance élément de la page auquel on affecte le behavior il va y avoir une requête HTTP pour charger le fichier .htc. Vous allez me dire que ce n'est pas un problème avec le cache du navigateur... Certes... si le navigateur gardait le fichier en cache ce ne serait pas un problème (du moins chez moi il n'est pas conservé en cache... mais ça ne change rien car mes paramètres sont de vérifier la présence d'une nouvelle version des fichiers à chaque visite de la page... d'où des requêtes supplémentaires). Autrement dit si vous avez un tableau de 75 lignes il chargera 75 fois le fichier .htc ce qui n'est pas toujours très rapide (surtout par modem !).

Second problème... J'ai parlé des variables que l'on pouvait déclarer dans un script. J'ai même dit que la variable était locale à chaque instance du behavior. Ca signifie que si vous déclarez 5 variables et que vous avez 20 instances du behavior vous vous retrouvez avec une occupation mémoire de 5 x 20 = 100 variables. Sur des machines puissantes ce n'est pas trop un problèmes mais il faut conserver ce fait en mémoire. La solution consiste à créer des variables dans le document appelant via un script d'initialisation puis de faire référence à ces variables dans le script... Pour peu que l'on puisse globaliser les variables bien entendu.

Conclusion

Ma conclusion c'est que j'aime bien les behaviors. Ca comble une lacune du javascript et des feuilles de style et permet de créer des composants un peu complexes réutilisables. Sur le site de Microsoft par exemple ils utilisent les behaviors pour gérer des pseudo treeviews de façon très simple. En cherchant un peu on arrive à des résultats spectaculaires comme par exemple l'utilisation de HTML dans les infobulles de Internet Explorer (celles qui s'affichent quand il y a un attribut TITLE sur un lien par exemple) permettant ainsi de jouer sur les retour à la ligne ou de mettre des images.

Enfin une dernière remarque : je n'ai fait que vous donner un aperçu de la puissance des behaviors. Si je vous dit que depuis IE5.5 on peut créer des composants appelables comme des balises en HTML, que l'on peut se faire des behavior en C++ ou qu'il y en a d'inclus dans IE5 pour gérer la persistance vous aurez probablement envie d'aller plus loin... en lisant la doc complète sur le site de Microsoft (attention, c'est en anglais).

Retrouvez-moi sur

Facebook LinkedIn Viadeo

Photo aléatoire