XII. Le modèle d'objet document▲
Dans le chapitre 11 nous avons vu les objets JavaScript qui font référence aux balises form et input du document HTML. De tels objets font partie d'une structure appelée le modèle d'objet document (DOM). Chaque élément du document est représenté dans ce modèle, on peut l'examiner et interagir avec lui.
Les documents HTML ont ce qu'on peut appeler une structure hiérarchique. Chaque élément (ou balise) à l'exception de la balise de premier niveau <html> est contenu dans un autre élément, son parent. Cet élément peut en retour contenir d'autres éléments. Vous pouvez vous le représenter comme une sorte d'arbre généalogique.
Le modèle document objet est basé sur une telle vue du document. Veuillez noter que l'arbre contient deux types d'éléments : les nœuds, représentés comme des boîtes bleues et de simples morceaux de texte. Les morceaux de texte sont comme nous le verrons assez différents des autres éléments. L'une de ces différences est qu'ils n'ont jamais d'enfants.
Ouvrez le fichier example_alchemy.html qui contient le document présenté dans l'image et attachez-y la console.
attach
(
window
.open
(
"example_alchemy.html"
));
L'objet de la racine de l'arbre document, le nœud html, peut-être atteint via la propriété documentElement de l'objet document. La plupart du temps, nous avons plutôt besoin de la partie body du document qui se trouve à document.body.
Les liens entre ces nœuds sont disponibles sous forme de propriétés de l'objet nœud. Chaque objet DOM possède une propriété parentNode qui fait référence à l'objet dans lequel il est contenu, si objet il y a. Ces parents ont aussi des liens pointant vers leurs enfants. Mais parce qu'il peut y avoir plusieurs enfants, ils sont stockés dans un pseudotableau appelé childNodes.
show
(
document
.
body);
show
(
document
.
body.
parentNode);
show
(
document
.
body.
childNodes.
length);
Par commodité, il y a aussi des liens appelés firstChild et lastChild, pointant respectivement au premier et au dernier enfant à l'intérieur d'un nœud ou null quand il n'y a pas d'enfant.
show
(
document
.
documentElement.
firstChild);
show
(
document
.
documentElement.
lastChild);
Enfin, il y a des propriétés nommées nextSibling et previousSibling, qui pointent vers les nœuds présents aux côtés d'un autre nœud - les nœuds qui sont des enfants du même parent, venant avant ou après le nœud courant. Encore une fois, lorsque ces nœuds ne sont pas présents, la valeur de ces propriétés est null.
show
(
document
.
body.
previousSibling);
show
(
document
.
body.
nextSibling);
Pour savoir si un nœud représente un simple morceau de texte ou un nœud HTML, nous pouvons jeter un œil à sa propriété nodeType. Elle contiendra un nombre, 1 pour un nœud classique et 3 pour un nœud texte. Il existe en fait d'autres sortes d'objets qui possèdent un nodeType, comme l'objet document qui vaudra 9, mais l'usage le plus commun de cette propriété est la distinction entre les nœuds textes et les autres nœuds.
function isTextNode
(
noeud) {
return noeud.
nodeType ==
3
;
}
show
(
isTextNode
(
document
.
body));
show
(
isTextNode
(
document
.
body.
firstChild.
firstChild));
Les nœuds classiques ont une propriété appelée nodeName, indiquant le type de balise HTML qu'ils représentent. En revanche, les nœuds textes ont une propriété nodeValue, ayant pour valeur leur contenu texte.
show
(
document
.
body.
firstChild.
nodeName);
show
(
document
.
body.
firstChild.
firstChild.
nodeValue);
Les propriétés nodeName sont toujours mises en majuscules, c'est quelque chose qui doit être pris en compte si jamais vous voulez les comparer à quoi que ce soit.
function isImage
(
noeud) {
return !
isTextNode
(
noeud) &&
noeud.
nodeName ==
"IMG"
;
}
show
(
isImage
(
document
.
body.
lastChild));
Ex. 12.1
Écrivez une fonction asHTML qui, appelée avec un nœud DOM, produira une chaîne représentant le texte HTML de ce nœud et de ses éléments. Vous pouvez ignorer les attributs, afficher juste les nœuds comme <nodename>. La fonction escapeHTML du chapitre 10 est disponible afin d'échapper correctement le contenu des nœuds textes.
Indice : récursion !
function asHTML
(
noeud) {
if (
isTextNode
(
noeud))
return escapeHTML
(
noeud.
nodeValue);
else if (
noeud.
childNodes.
length ==
0
)
return "<"
+
noeud.
nodeName +
"/>"
;
else
return "<"
+
noeud.
nodeName +
">"
+
map
(
asHTML,
noeud.
childNodes).join
(
""
) +
"</"
+
noeud.
nodeName +
">"
;
}
print
(
asHTML
(
document
.
body));
En réalité, les nœuds ont déjà quelque chose de similaire à asHTML. Leur propriété innerHTML peut être utilisée afin de récupérer le texte HTML à l'intérieur du nœud, sans les balises du nœud en question. Quelques navigateurs Web, mais pas tous, prennent aussi en charge la propriété outerHTML, qui inclut le nœud lui-même.
print
(
document
.
body.
innerHTML);
Certaines de ces propriétés peuvent aussi être modifiées. Modifier le innerHTML d'un nœud ou la nodeValue d'un nœud texte changera son contenu. À noter que dans le premier cas, la chaîne donnée est interprétée comme du HTML alors que dans le second cas elle est interprétée comme du simple texte.
document
.
body.
firstChild.
firstChild.
nodeValue =
"Chapitre 1 : La grande importance de la bouteille"
;
Ou...
document
.
body.
firstChild.
innerHTML =
"Connaissiez-vous déjà la balise « blink » ? <blink>Oh joie !</blink>"
;
Nous avons accédé à des nœuds au travers d'une série de propriétés firstChild et lastChild. Cela peut fonctionner, mais c'est assez verbeux et facilement cassable -: si nous ajoutons un autre nœud au début de notre document, document.body.firstChild ne pointera plus sur l'élément h1 et si le code prétend le contraire il se trompe. En plus de cela, certains navigateurs Web ajouteront des nœuds texte pour des choses comme les espaces et les retours à la ligne entre les balises alors que d'autres non. La représentation exacte de l'arbre DOM peut varier.
Comme autre possibilité, il vous est possible de donner un attribut id aux éléments auxquels vous avez besoin d'accéder. Dans la page d'exemple, l'image à un id "image", nous pouvons l'utiliser pour retrouver l'image.
var image
=
document
.getElementById
(
"image"
);
show
(
image
.
src);
image
.
src =
"img/ostrich.png"
;
Quand vous tapez getElementById, notez que la dernière lettre est en minuscule. Faites donc attention, lorsque vous le taperez souvent, au syndrome du canal carpien. Parce que document.getElementById est un nom ridiculement long pour une opération aussi commune, l'abréger par $ est devenu une convention au sein des développeurs JavaScript. $, comme vous vous en souvenez peut-être, est considéré comme une lettre par JavaScript et c'est donc un nom de variable valide.
Les nœuds DOM ont aussi une méthode getElementsByTagName (un autre nom sympa et court), qui appelée avec un nom de balise, retourne un tableau de tous les nœuds de ce type contenu dans le nœud sur lequel la méthode a été appelée.
show
(
document
.
body.getElementsByTagName
(
"BLINK"
)[
0
]
);
Une autre chose que nous pouvons faire avec ces nœuds est d'en créer de nouveaux nous-mêmes. Cela rend possible l'ajout d'éléments dans un document, qui pourront être utilisés pour créer des effets intéressants. Malheureusement l'interface permettant cela est extrêmement mal fichue. Mais il est possible de remédier à cela avec des fonctions d'aide.
L'objet document possède les méthodes createElement et createTextNode. La première est utilisée pour créer un nœud classique, la seconde, comme son nom le suggère, pour créer un nœud texte.
var deuxiemeEntete =
document
.createElement
(
"H1"
);
var deuxiemeChapitre =
document
.createTextNode
(
"Chapitre 2 : Magie intense"
);
Nous voulons ensuite mettre le titre dans l'élément h1, puis ajouter cet élément au document. Le moyen le plus simple de le faire est la méthode appendChild qui peut-être appelée sur chaque nœud qui n'est pas un nœud texte.
deuxiemeEntete.appendChild
(
deuxiemeChapitre);
document
.
body.appendChild
(
deuxiemeEntete);
Souvent, vous voudrez aussi ajouter des attributs à ces nouveaux nœuds . Par exemple, une balise img (image) est plutôt inutile sans la propriété src qui dit au navigateur quelle image il doit afficher. La plupart des attributs peuvent être retrouvés directement comme des propriétés du nœud DOM mais il y a aussi les méthodes setAttribute et getAttribute, qui sont utilisées pour accéder aux attributs de façon plus générale :
var nouvelleImage =
document
.createElement
(
"IMG"
);
nouvelleImage.setAttribute
(
"src"
,
"img/Hiva Oa.png"
);
document
.
body.appendChild
(
nouvelleImage);
show
(
nouvelleImage.getAttribute
(
"src"
));
Mais, lorsque l'on veut créer davantage que quelques nœuds simples, il devient assez assommant de créer chaque nœud avec un appel vers document.createElement ou document.createTextNode, et ensuite d'y ajouter les attributs et les éléments un par un. Heureusement, il n'est pas trop difficile d'écrire une fonction qui ferait le plus gros du travail pour nous. Avant de s'y mettre, il y a un petit détail qu'il faut prendre en compte : la méthode setAttribute, qui fonctionne correctement sur la plupart des navigateurs, ne fonctionne pas toujours sur Internet Explorer. Les noms de certains attributs HTML ont déjà un sens particulier en JavaScript, de ce fait, la propriété de l'objet correspondant obtient un nom ajusté. Plus spécifiquement, l'attribut class devient className, for devient htmlFor et checked est renommé en defaultChecked. Sur Internet Explorer, setAttribute et getAttribute fonctionnent aussi avec ces noms ajustés, à la place des noms HTML originaux ce qui peut être source de confusion. En plus de cela l'attribut style, qui sera abordé plus tard dans ce chapitre avec class, ne peut être défini avec setAttribute sur ce navigateur.
Une solution de contournement pourrait ressembler à quelque chose comme ça :
function setNodeAttribute
(
noeud,
attribut,
valeur) {
if (
attribut ==
"class"
)
noeud.
className =
valeur;
else if (
attribut ==
"checked"
)
noeud.
defaultChecked =
valeur;
else if (
attribut ==
"for"
)
noeud.
htmlFor =
valeur;
else if (
attribut ==
"style"
)
noeud.
style.
cssText =
valeur;
else
noeud.setAttribute
(
attribut,
valeur);
}
À chaque fois qu'Internet Explorer dévie du comportement des autres navigateurs, il fait quelque chose qui fonctionne dans tous les cas. Ne vous inquiétez pas des détails, c'est ce genre d'astuces sales dont nous aimerions ne pas avoir besoin mais que les navigateurs non conformes nous obligent à écrire. Considérant ceci, il est possible d'écrire une simple fonction pour créer des éléments DOM.
function dom
(
nom,
attributs) {
var noeud =
document
.createElement
(
nom);
if (
attributs) {
forEachIn
(
attributs,
function(
nom,
valeur) {
setNodeAttribute
(
noeud,
nom,
valeur);
}
);
}
for (
var i =
2
;
i <
arguments.
length;
i++
) {
var noeudEnfant =
arguments[
i];
if (
typeof noeudEnfant ==
"string"
)
noeudEnfant =
document
.createTextNode
(
noeudEnfant);
noeud.appendChild
(
noeudEnfant);
}
return noeud;
}
var nouveauParagraphe =
dom
(
"P"
,
null,
"Un paragraphe avec un "
,
dom
(
"A"
,
{
href
:
"http://fr.wikipedia.org/wiki/Alchimie"
},
"lien"
),
" à l'intérieur."
);
document
.
body.appendChild
(
nouveauParagraphe);
La fonction dom crée un arbre DOM. Son premier argument donne le nom de la balise du nœud, son second argument est un objet contenant l'attribut du nœud, ou null quand aucun attribut n'est requis. Après quoi, n'importe quel nombre d'arguments peut suivre et ils seront ajoutés au nœud comme enfants nœuds. Quand des chaînes apparaissent ici, elles sont ajoutées dans un nœud texte.
appendChild n'est pas le seul moyen d'insérer des nœuds dans un autre nœud. Quand le nouveau nœud ne doit pas apparaître à la fin de son parent, la méthode insertBefore peut-être utilisée pour le placer avant un autre nœud enfant. Elle prend le nouveau nœud comme premier argument et l'élément existant comme second argument.
var lien =
nouveauParagraphe.
childNodes[
1
];
nouveauParagraphe.insertBefore
(
dom
(
"STRONG"
,
null,
"super "
),
lien);
Si un nœud possédant déjà un parentNode est placé ailleurs, il est automatiquement supprimé de sa position actuelle - les nœuds ne peuvent pas exister dans le document à plus d'un endroit à la fois.
Quand un nœud doit être remplacé par un autre, utilisez la méthode replaceChild, qui prend encore le nouveau nœud comme premier argument et le nœud existant comme second argument.
nouveauParagraphe.replaceChild
(
document
.createTextNode
(
"mauvais "
),
nouveauParagraphe.
childNodes[
1
]
);
Et finalement, il y a removeChild pour supprimer un nœud enfant. À noter que cette méthode doit être appelée sur le parent du nœud à supprimer, en lui donnant l'enfant comme argument.
nouveauParagraphe.removeChild
(
nouveauParagraphe.
childNodes[
1
]
);
Ex. 12.2
Écrivez la fonction utile removeElement qui supprime de son nœud parent le nœud DOM donné en paramètre
function removeElement
(
noeud) {
if (
noeud.
parentNode)
noeud.
parentNode.removeChild
(
noeud);
}
removeElement
(
nouveauParagraphe);
Pendant la création de nœuds et le déplacement de nœuds, il est nécessaire de prendre en compte la règle suivante : les nœuds ne sont pas autorisés à être insérés dans un autre document que celui dans lequel ils ont été créés. Ce qui veut dire que si vous avez des pages ou des fenêtres supplémentaires ouvertes, vous ne pouvez pas prendre un fragment de document de l'un pour le placer dans un autre et que les nœuds créés avec les méthodes d'un objet document doivent rester dans ce document. Certains navigateurs, notamment Firefox, n'appliquent pas cette restriction, de ce fait un programme qui la viole pourra fonctionner correctement dans ce navigateur mais pas dans d'autres.
Un exemple de quelque chose d'utile qui peut être fait avec cette fonction dom est un programme qui prend des objets JavaScript et en fait un résumé dans un tableau. Les tableaux, en HTML, sont créés avec un ensemble de balises commençant par t, quelque chose comme :
<table>
<tbody>
<tr> <th>Arbre </th>
<th>Fleurs </th>
</tr>
<tr> <td>Pommier</td>
<td>Blanches</td>
</tr>
<tr> <td>Corail </td>
<td>Rouges </td>
</tr>
<tr> <td>Pin </td>
<td>Aucune </td>
</tr>
</tbody>
</table>
Chaque élément tr est une ligne du tableau. Les éléments th et td sont les cellules du tableau, td pour des cellules normales, th pour les cellules d'en-tête qui seront affichées dans un style plus visible. La balise tbody (table body) n'a pas à être incluse quand un tableau est écrit en HTML, mais s'il est construit avec des nœuds DOM, elle doit être ajoutée car Internet Explorer refuse d'afficher les tableaux créés sans tbody.
Ex. 12.3
La fonction makeTable prend deux tableaux en arguments. Le premier contient les objets JavaScript qu'il doit récapituler et le second contient des chaînes, qui nomment les colonnes du tableau et les propriétés des objets qui doivent être affichées dans ces colonnes. Ce qui suit devrait produire le tableau ci-dessus :
makeTable
([{
Arbre
:
"Pommier"
,
Fleurs
:
"Blanches"
},
{
Arbre
:
"Corail"
,
Fleurs
:
"Rouges"
},
{
Arbre
:
"Pin"
,
Fleurs
:
"Aucune"
}],
[
"Arbre"
,
"Fleurs"
]
);
Écrivez cette fonction.
function makeTable
(
donnees,
colonnes) {
var ligneEntete =
dom
(
"TR"
);
forEach
(
colonnes,
function(
nom) {
ligneEntete.appendChild
(
dom
(
"TH"
,
null,
nom));
}
);
var corps =
dom
(
"TBODY"
,
null,
ligneEntete);
forEach
(
donnees,
function(
objet) {
var ligne =
dom
(
"TR"
);
forEach
(
colonnes,
function(
nom) {
ligne.appendChild
(
dom
(
"TD"
,
null,
String(
objet[
nom]
)));
}
);
corps.appendChild
(
ligne);
}
);
return dom
(
"TABLE"
,
null,
corps);
}
var table =
makeTable
(
document
.
body.
childNodes,
[
"nodeType"
,
"tagName"
]
);
document
.
body.appendChild
(
table);
N'oubliez par de convertir les valeurs des objets en chaînes avant de les ajouter au tableau - notre fonction dom comprend seulement les chaînes et les nœuds DOM.
Le sujet des feuilles de style est étroitement lié à HTML et au modèle document objet. C'est un vaste sujet et je ne l'aborderai pas entièrement. Mais quelques notions sur les feuilles de style sont nécessaires pour beaucoup de techniques intéressantes en JavaScript, nous allons donc en voir les rudiments.
Aux débuts de l'HTML, le seul moyen de changer l'apparence des éléments dans un document était de leur donner des attributs supplémentaires ou de les contenir dans des balises supplémentaires. Comme center qui permet de centrer les éléments horizontalement ou font pour changer le style ou la couleur de la police. La plupart du temps, cela veut dire que si vous vouliez que les paragraphes ou les tableaux de votre document apparaissent d'une certaine façon, vous deviez ajouter un ensemble d'attributs et de balises à chacun des éléments. Cela a rapidement ajouté beaucoup de « bruits parasites » aux documents et les a rendus particulièrement compliqués à écrire ou à modifier à la main.
Évidemment, les gens étant des singes ingénieux, quelqu'un a proposé une solution. Les feuilles de style sont un moyen de déclarer quelque chose comme « Dans ce document, tous les paragraphes utiliseront la police Comic Sans et seront mauves et tous les tableaux auront une fine bordure verte ». Vous spécifiez ces règles une fois pour toutes, en haut du document ou dans un fichier séparé et elles affecteront le document entier. Voici, pour exemple, une feuille de style permettant d'afficher les en-têtes centrés avec une taille de 22 points et de faire en sorte que les paragraphes utilisent la police et la couleur mentionnées plus haut quand ils appartiennent à la classe « moche ».
<style type
=
"text/css"
>
h1 {
font-size:
22
pt;
text-align:
center
;
}
p.moche
{
font-family:
Comic Sans MS;
color:
purple
;
}
</style>
Les classes sont un concept lié aux styles. Si vous avez différentes sortes de paragraphes, des moches et des jolis par exemple, et que vous ne voulez pas attribuer le style à tous les éléments p, alors les classes peuvent être utilisées pour les distinguer. Le style précédent ne sera appliqué qu'aux paragraphes comme :
<p class
=
"moche"
>
Miroir, miroir...</p>
Et c'est aussi le sens de la propriété className qui était brièvement mentionnée dans la fonction setNodeAttribute. L'attribut style peut être utilisé afin d'ajouter des éléments de style directement à un élément. Par exemple, ceci donne pour notre image une bordure en trait continu de 4 pixels ('px').
setNodeAttribute
(
$(
"image"
),
"style"
,
"border-width: 4px; border-style: solid;"
);
On peut aller bien plus loin avec les styles : certains sont hérités par les nœuds enfants de leurs nœuds parents et interfèrent les uns avec les autres de façon complexe et intéressante, mais en ce qui concerne la programmation DOM, la chose la plus importante à savoir est que chaque nœud DOM possède une propriété style, qui peut être utilisée pour manipuler le style de ce nœud et qu'il y a quelques styles qui peuvent être utilisés pour que les nœuds fassent des choses extraordinaires.
Cette propriété style fait référence à un objet, qui possède des propriétés pour chaque élément de ce style. Nous pouvons par exemple décider que la bordure de l'image sera verte.
$(
"image"
).
style.
borderColor =
"green"
;
show
(
$(
"image"
).
style.
borderColor);
Veuillez noter que dans les feuilles de style, les mots sont séparés par des traits d'union comme dans border-color, alors qu'en JavaScript, les lettres majuscules sont utilisées pour séparer les différents mots, comme dans borderColor.
Un exemple de style très pratique est display : none. Il peut être utilisé pour temporairement cacher un nœud : quand style.display est "none", l'élément n'apparaît plus du tout à la personne qui visualise le document, même s'il existe. Plus tard, display peut être affecté d'une chaîne vide et l'élément réapparaîtra.
$(
"image"
).
style.
display =
"none"
;
Et pour faire revenir notre image :
$(
"image"
).
style.
display =
""
;
Il existe d'autres types de style dont on peut user et abuser de façon intéressante, ceux liés au positionnement. Dans un simple document HTML, le navigateur s'occupe de déterminer la position de l'écran et de tous les éléments - chaque élément est mis à la suite ou au-dessous de l'élément qui le précède et les nœuds ne se chevauchent pas (en général).
Quand son style position est à "absolute", un nœud est retiré du flux normal du document. Il n'a plus sa place dans le document mais en quelque sorte au-dessus de lui. Les styles left et top peuvent ensuite être utilisés pour influencer sa position. Ceux-ci peuvent être utilisés pour de nombreux usages, que ce soit pour faire un nœud qui suivrait obstinément le curseur de la souris ou pour faire des « fenêtres » qui s'ouvriraient au-dessus du reste du document.
$(
"image"
).
style.
position =
"absolute"
;
var angle =
0
;
var spin =
setInterval
(
function(
) {
angle +=
0
.
1
;
$(
"image"
).
style.
left = (
100
+
100
*
Math.cos
(
angle)) +
"px"
;
$(
"image"
).
style.
top
= (
100
+
100
*
Math.sin
(
angle)) +
"px"
;
},
100
);
Si vous n'êtes pas familier avec la goniométrie, faites-moi confiance quand je vous dis que le cosinus et le sinus sont utilisés pour construire des coordonnées reposant sur le contour d'un cercle. Dix fois par seconde, l'angle sur lequel on a placé l'image est modifié et les nouvelles coordonnées sont calculées. C'est une erreur commune lorsqu'on attribue des styles comme cela d'oublier d'ajouter 'px' à la valeur. Dans la plupart des cas, attribuer un nombre sans unité à un style ne fonctionne pas donc vous devez ajouter 'px' pour pixels, '%' pour pourcentage, 'em' pour cadratin (la largeur d'un caractère M) ou encore 'pt' pour points.
(Maintenant, mettons une image pour nous reposer encore...)
clearInterval
(
spin);
L'emplacement qui est traité comme 0,0 pour ces positions dépend de la place du nœud dans le document. Lorsqu'il est placé à l'intérieur d'un autre nœud qui a position : absolute ou position : relative, le coin supérieur gauche de ce nœud est utilisé. Sinon, c'est le coin supérieur gauche du document.
Un dernier aspect des nœuds DOM avec lequel il est sympa de jouer est leur taille. Il existe des types de style nommés width (largeur) et height (hauteur), qui sont utilisés pour définir la taille absolue d'un élément.
$(
"image"
).
style.
width =
"400px"
;
$(
"image"
).
style.
height =
"200px"
;
Mais lorsque vous avez besoin de définir précisément la taille d'un élément, il y a un problème épineux à prendre en compte. Certains navigateurs, dans certaines circonstances, considèrent que ces tailles correspondent à la taille extérieure de l'objet, incluant les bordures et les marges intérieures. D'autres navigateurs, dans d'autres circonstances, ne tiennent pas compte de la largeur des bordures et des marges. Ainsi, si vous définissez la taille d'un objet qui a une bordure ou une marge, il n'apparaîtra pas toujours à la même taille.
Heureusement, vous pouvez examiner la taille intérieure et extérieure du nœud, ce qui, si vous avez vraiment besoin de définir précisément la taille de quelque chose, peut être utilisé pour compenser le comportement du navigateur. Les propriétés offsetWidth et offsetHeight vous donnent la taille extérieure de votre élément (la place qu'il occupe dans le document), tandis que les propriétés clientWidth et clientHeight vous donnent la place à l'intérieur de l'objet, s'il y en a.
print
(
"Dimension extérieure: "
,
$(
"image"
).
offsetWidth,
" sur "
,
$(
"image"
).
offsetHeight,
" pixels."
);
print
(
"Dimension intérieure: "
,
$(
"image"
).
clientWidth,
" sur "
,
$(
"image"
).
clientHeight,
" pixels."
);
Si vous avez consciencieusement suivi et utilisé tous les exemples de ce chapitre et peut-être effectué vous-même quelques expériences supplémentaires, vous aurez complètement saccagé le malheureux document initial qui nous a servi de point de départ. Laissez-moi vous faire les gros yeux une minute et vous dire de ne surtout pas faire subir le même traitement à de vraies pages. Parfois la tentation sera grande d'ajouter des tas de choses bling-bling et qui bougent. Retenez-vous, sinon vos pages deviendront certainement illisibles ou même, si vous allez assez loin, pourraient provoquer de temps en temps une crise d'épilepsie.