II. Création d'un HtmlEditTable à partir d'une table HTML existante▲
Vous avez peut-être tardivement entendu parler de la révolutionnaire (mytho?) HtmlEditTable et vous aimeriez l'utiliser sans pour autant devoir réécrire vos pages. Eh oui! Vous avez déjà construit vos tables en HTML ou via un script et il serait intéressant de leur ajouter les capacités de la HtmlEditTable sans toucher à l'existant. Et bien, allons-y !
II-A. Page de test▲
Notre page de test est simple : une table HTML suivie d'un script de création d'un HtmlEditEditTable à partir de la table HTML. Le script consiste en l'appel du constructeur de la classe HtmlEditTable auquel on passe l'objet paramètre avec la propriété « table » qui n'est autre que l'objet table.
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
<
html>
<
head>
<
script type=
"text/javascript"
src=
"HtmlEditTable.js"
></
script>
<
style type=
"text/css"
>
@import url
(
HtmlEditTable.
css);
</
style>
</
head>
<
body>
<
table id=
"tableHTML"
>
<
thead>
<
tr>
<
td>
head</
td>
<
td>
head</
td>
<
td>
head</
td>
<
td>
head</
td>
<
td>
head</
td>
</
tr>
</
thead>
<
tbody>
<
tr>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
</
tr>
<
tr>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
</
tr>
<
tr>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
<
td>
data</
td>
</
tr>
</
tbody>
</
table>
<
br/>
<
script>
var tableHTML =
document
.getElementById
(
"tableHTML"
);
var tableEdit =
new HtmlEditTable
({
"table"
:
tableHTML}
);
</
script>
</
body>
</
html>
II-B. JS : HtmlEditTable(param)▲
Si la table HTML existe, alors passons-la au constructeur de la classe HtmlEditTable. Bref rappel, le constructeur accepte un unique paramètre qui est un objet disposant des propriétés (facultatives) suivantes :
Propriétés du paramètre du constructeur :
- le nombre de colonnes (X) ou la liste des noms de colonnes (Xn) ;
- le nombre de lignes (Y) ou la liste des noms de lignes (Yn) ;
- les données (data) ;
- le titre de la table (caption) ;
- la liste des en-têtes de colonnes (head).
À cette liste de propriétés possibles, on ajoute donc la suivante :
Nouvelle propriété du paramètre du constructeur
- la table HTML (table) à étendre en HtmlEditTable.
Concrètement l'impact de cette fonctionnalité se situe au niveau du constructeur :
HtmlEditTable =
function(
){
if (
arguments.
length >
0
&&
arguments[
0
].
table){
this.Transform
(
arguments);
}
else{
this.
control =
document
.createElement
(
"table"
);
if (
arguments.
length >
0
){
this.Build
(
arguments[
0
]
);
}
}
this.
control.
cellSpacing =
0
;
this.
control.
cellPadding =
0
;
this.
control.
className =
"HtmlEditTable"
;
};
Que s'est-il passé? La nouveauté vient de l'instruction conditionnelle. Si la propriété table du paramètre existe, alors il s'agit d'étendre les fonctionnalités d'une table existante, sinon il s'agit de créer un HtmlEditTable de A à Z.
Dans le cas de l'extension d'une table, la fonction Transform() intervient. Son rôle est identique à celui de la fonction Build() à ceci près qu'au lieu d'initialiser le HtmlEditTable à partir des propriétés de la v1.0 du paramètre du constructeur, l'initialisation se base sur la table, propriété de la v2.0 :).
Transform
:
function(
args){
this.
columns =
[];
this.
lines =
[];
this.
headers =
[];
this.
control =
args[
0
].
table;
this.
caption =
this.
control.
caption;
for (
var i=
0
,
imax=
this.
control.
rows[
0
].
cells.
length;
i<
imax;
i++
){
this.
columns.push
(
""
+
i);
}
for (
var i=
0
,
imax=
this.
control.
rows.
length;
i<
imax;
i++
){
this.
lines.push
(
""
+
i);
}
if (
this.
control &&
this.
control.
tBodies){
for (
var i=
0
,
imax=
this.
control.
tBodies.
length;
i<
imax;
i++
){
var tBody =
this.
control.
tBodies[
i];
for (
var j=
0
,
jmax=
tBody.
rows.
length;
j<
jmax;
j++
){
for (
var k=
0
,
kmax=
tBody.
rows[
j].
cells.
length;
k<
kmax;
k++
){
var cell =
tBody.
rows[
j].
cells[
k];
cell.
tabIndex =
0
;
HtmlEditTableHelper.CellInitialize
(
this,
cell);
if (
cell.
childNodes.
length ==
0
){
cell.appendChild
(
document
.createTextNode
(
""
));
}
}
}
}
}
}
Dans un premier temps, la fonction Transform() :
- crée les arrays columns, lines et headers ;
- assigne la table à la propriété control ;
- assigne le titre (caption) de la table au HtmlEditTable.
Puis chaque colonne et chaque ligne sont parcourues afin d'initialiser les arrays columns et lines. Pour rappel, il s'agit des listes de noms de colonnes et de lignes. Ceux-ci sont initialisés comme étant l'indice de la colonne ou de la ligne dans la table.
Pour finir, toutes les cellules des tBody sont parcourues et leurs fonctionnalités sont étendues grâce à la fonction HtmlEditTableHelper.CellInitialize(). Les cellules n'ayant pas de contenu se voient ajouter un nœud texte vide.
Pour finir ? Oui, mais non… Si vous disposez d'un outil pour visualiser le DOM de votre document sous Internet Explorer, vous constaterez que la structure de la table est « propre ». Par contre avec d'autres navigateurs (Firefox, Chrome, pour ne citer qu'eux) vous remarquerez qu'il y a pas mal de nœuds texte qui polluent la table. Ces navigateurs interprètent les retours chariot comme des nœuds texte et donc ces nœuds s'intercalent avec les nœuds « légitimes » de la table.
Comme par la suite nous voudrons naviguer au clavier entre les cellules de la table, il est préférable de nettoyer la structure de cette dernière dès maintenant. Cela facilite les développements futurs et rendra cohérente la structure du contrôle qu'il ait été généré à partir d'une table HTML préexistante ou non (car lorsqu'on construit le contrôle à partir de rien, comme dans la v1.0, il n'y a pas de nœuds parasites).
Ajoutons à la classe utilitaire Tools une fonction de suppression des nœuds texte :
RemoveTextNode
:
function(
o){
if (
o ==
null){
return;
}
for (
var i=
o.
childNodes.
length-
1
;
i>-
1
;
i--
){
var child =
o.
childNodes[
i];
if (
child.
nodeName ==
"#text"
){
o.removeChild
(
child);
}
}
}
Et utilisons-la dans la fonction HtmlEditTable.prototype.Transform pour nettoyer la table des nœuds texte parasites :
Transform
:
function(
args){
this.
columns =
[];
this.
lines =
[];
this.
headers =
[];
this.
control =
args[
0
].
table;
this.
caption =
this.
control.
caption;
for (
var i=
0
,
imax=
this.
control.
rows[
0
].
cells.
length;
i<
imax;
i++
){
this.
columns.push
(
""
+
i);
}
for (
var i=
0
,
imax=
this.
control.
rows.
length;
i<
imax;
i++
){
this.
lines.push
(
""
+
i);
}
if (
this.
control &&
this.
control.
tBodies){
for (
var i=
0
,
imax=
this.
control.
tBodies.
length;
i<
imax;
i++
){
var tBody =
this.
control.
tBodies[
i];
for (
var j=
0
,
jmax=
tBody.
rows.
length;
j<
jmax;
j++
){
for (
var k=
0
,
kmax=
tBody.
rows[
j].
cells.
length;
k<
kmax;
k++
){
var cell =
tBody.
rows[
j].
cells[
k];
cell.
tabIndex =
0
;
HtmlEditTableHelper.CellInitialize
(
this,
cell);
}
}
}
}
if (
this.
control){
Tools.RemoveTextNode
(
this.
control);
if (
this.
control.
tHead){
var tHead =
this.
control.
tHead;
Tools.RemoveTextNode
(
tHead);
for (
var i=
0
,
imax=
tHead.
rows.
length;
i<
imax;
i++
){
Tools.RemoveTextNode
(
tHead.
rows[
i]
);
}
}
if (
this.
control.
tBodies){
for (
var i=
0
,
imax=
this.
control.
tBodies.
length;
i<
imax;
i++
){
var tBody =
this.
control.
tBodies[
i];
Tools.RemoveTextNode
(
tBody);
for (
var j=
0
,
jmax=
tBody.
rows.
length;
j<
jmax;
j++
){
Tools.RemoveTextNode
(
tBody.
rows[
j]
);
}
}
}
if (
this.
control.
tFoot){
var tFoot =
this.
control.
tFoot;
Tools.RemoveTextNode
(
tFoot);
for (
var i=
0
,
imax=
tFoot.
rows.
length;
i<
imax;
i++
){
Tools.RemoveTextNode
(
tFoot.
rows[
i]
);
}
}
}
}
Vous allez rire, mais… c'est fini :) voir la démo - télécharger les sources
Cette fonction peut être optimisée au niveau des boucles. Cependant j'ai préféré séparer le « nettoyage » de la table de l'initialisation des cellules, surtout pour le côté pédagogique de l'article. Libre à vous d'optimiser la fonction si vous pensez avoir des problèmes de performances à ce niveau.