Aperçu de l'attribut contenteditable en HTML5

lundi 19 avril 2010

L'HyperText Markup Language, ou HTML, est le langage permettant de décrire la composition des pages Web que le navigateur interprète afin d'afficher le contenu à l'écran. Les spécifications de ce langage sont établies par le World Wide Web Consortium (W3C). La cinquième version du HTML, en cours d'élaboration, est déjà partiellement intégrée à la plupart des navigateurs modernes. La balise <video> a monopolisé l'attention pendant un temps, mais l'HTML 5 offre d'autres nouveautés, dont le très important attribut contenteditable.

L’HyperText Markup Language, ou HTML, est le langage permettant de décrire la composition des pages Web que le navigateur interprète afin d’afficher le contenu à l’écran. Les spécifications de ce langage sont établies par le World Wide Web Consortium (W3C). La cinquième version du HTML, en cours d’élaboration, est déjà partiellement intégrée à la plupart des navigateurs modernes. La balise <video> a monopolisé l’attention pendant un temps, mais l’HTML 5 offre d’autres nouveautés, dont le très important attribut contenteditable.

Utilité de l’attribut contenteditable

Le Web 2.0 est caractérisé par la transformations des internautes de simples lecteurs passifs en producteurs de contenu. L’exemple typique est Wikipédia, l’encyclopédie collaborative dans laquelle chaque internaute peut apporter sa contribution. D’un point de vue technique, cette transformation s’appuie sur des technologies bien connues depuis quelques années, comme Ajax, qui permet aux pages Web d’abandonner leur état purement statique pour devenir interactives. L’attribut contenteditable permet également cela, mais de manière plus simple et plus efficace.

Cet attribut permet de rendre n’importe quel conteneur, dans une page Web, directement modifiable. L’internaute a l’impression d’être face à un logiciel de traitement de texte plutôt qu’à une page Web.

Reprenons l’exemple de Wikipédia. Le lecteur qui souhaite corriger une erreur dans un article devra cliquer sur un lien, appelé «Modifier», qui le redirigera vers une page avec une zone d’édition du texte. Il devra ensuite rechercher le passage à corriger dans la zone d’édition (ce qui peut être pénible, en fonction de la longueur du texte), effectuer la modification, puis soumettre en formulaire en cliquant sur un bouton «Enregistrer les modifications». Au final, il aura dû charger deux pages, en plus de la page contenant l’article, avec tout ce que cela implique – lenteur du chargement, perte de vue du texte avec le passage d’une page à l’autre, etc. La balise contenteditable résout ce problème en permettant d’effectuer les modifications directement sur la page d’origine.

Démonstration de l’attribut contenteditable

Voici une démonstration. Il suffit de cliquer sur le texte ci-dessous pour le rendre directement modifiable :

Modifiez-moi !

L’utilisation de cette balise est un jeu d’enfant. Pour réaliser l’exemple ci-dessus, il a suffi d’écrire ceci :

<span contenteditable="true">Modifiez-moi !</span>

Le conteneur utilisé est un <span>, mais cela fonctionne de la même manière avec les autres conteneurs, notamment <div> et <p>. A l’heure actuelle, l’attribut contenteditable fonctionne avec Firefox 3.6, Safari 4, Opera 10.5, Chrome 5.

Récupération des modifications avec JavaScript

Définir un conteneur comme étant modifiable –c’est-à-dire offrir à l’utilisateur la possibilité de modifier le contenu– ne sert à rien si l’on n’enregistre pas les modifications. L’attribut contenteditable ne permet pas, à lui seul, de faire cela. Son rôle se limite à rendre un conteneur modifiable. Il faudra donc utiliser JavaScript pour récupérer les modifications, puis pour les enregistrer (dans une base de données, par exemple).

Voici un exemple complet de la construction, pas à pas, d’une page qui offre à l’internaute de modifier un paragraphe de texte, et qui récupère ensuite les modifications grâce à JavaScript.

On commence par définir la structure de la page. Sur ce point, le HTML 5 ne change rien par rapport à la version précédente :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>test html5</title>
</head>
<body>
</body>
</html>

On insère ensuite, dans le corps de cette page, un paragraphe modifiable avec l’id test :
<body>
<p id="test" contenteditable="true">
Lorem Impsum...
</p>
</body>

On place, entre les balises <head> et </head>, un code JavaScript permettant : <ul> <li>De récupérer le conteneur grâce à son id (1ère fonction)</li> <li>De récupérer le contenu (2ème fonction)</li> <li>D’afficher un message avec ce contenu (3ème fonction)</li> </ul> <p><script type="text/javascript" charset="utf-8">
function $(element) { return document.getElementById(element) }
function $H(element) { return $(element).innerHTML }
function test() { alert($H('test')) }
</script>

Pour finir, on place un code JavaScript à la fin de la page, juste avant la balise </html>, qui permet : <ul> <li>D’attacher un gestionnaire d’événements au paragraphe modifiable : lorsque l’utilisateur valide sa modification, en cliquant en dehors de la zone modifiable, n’importe où sur la page, la fonction test() précédemment définie est appelée.</li> <li>D’activer la correction orthographique du navigateur dans le paragraphe modifiable.</li> </ul> <p><script type="text/javascript" charset="utf-8">
$('test').addEventListener("blur", test, false)
$('test').spellcheck = 'true'
</script>

L’élément modifiable, doté de l’attribut contenteditable, gère deux actions : focus et blur. La première est déclenchée lorsque l’utilisateur clique sur l’élément afin de le modifier, et la seconde lorsqu’il valide les modifications (un clic ailleurs sur la page, ou une pression sur la touche Tab, par exemple).

A noter qu’il est possible de rendre une page modifiable dans son ensemble, par JavaScript, grâce à l’instruction suivante :
document.designMode = 'true'

La page est terminée. Notre paragraphe peut être édité et les modifications sont récupérées par Javascript lorsque l’utilisateur les valide en sortant de la zone modifiable.

<!DOCTYPE html>

<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>test html5</title>
	<script type="text/javascript" charset="utf-8">
		function $(element) { return document.getElementById(element) }
		function $H(element) { return $(element).innerHTML }
		function test() { alert($H('test')) }
	</script>
</head>

<body>
<p id="test" contenteditable="true">
	Lorem Impsum...
</p>
</body>

<script type="text/javascript" charset="utf-8">
	$('test').addEventListener("blur", test, false)
	$('test').spellcheck = 'true'
</script>

</html>

Enregistrer les modifications avec Ajax

Dans l’exemple précédent, le nouveau contenu du paragraphe est simplement affiché dans une boîte de dialogue modale – alert() – : c’est tout ce que fait la fonction test(). Mais il est bien entendu possible de modifier cette fonction, afin d’enregistrer le nouveau contenu dans une base de données. Une requête AJAX serait particulièrement adaptée à cela.

permalink: /2010/04/19/contenteditable-html5/

Il existe de nombreux frameworks Ajax. Pour n’en citer que trois, parmi les plus célèbres : jQuery, Prototype, MooTools. Chacun a sa propre syntaxe ; c’est pourquoi il est difficile — et inutile – de créer ici un exemple qui conviendra à tous les lecteurs.

Voyons tout de même, dans les grandes lignes, comment faire. Côté JavaScript, on modifie la fonction test() pour récupérer l’id du paragraphe et son contenu :

function test()
{
test_contenu = document.getElementById('test').innerHTML

NB: JQuery et Prototype implémentent la fonction $() ; il faudra donc supprimer la fonction $(element) définie ci-dessus.

On rajoute ensuite l’appel Ajax, de manière différente selon le framework utilisé.

Exemple avec JQuery :

$.ajax({
type: "POST",
url: "test_update.php",
data: {contenu:test_contenu}
});
}

Exemple avec Prototype :

new Ajax.Updater("",
"test_update.php",
{
method:'post',
parameters: {contenu:test_contenu}
}
)
}

Reste ensuite à créer la page test_update.php, appelée par Ajax, afin de traiter les données transmises par la requête asynchrone.

<?php
if(!empty($_POST['contenu']))
{
$contenu = addslashes($_POST['contenu']);
$sql = "UPDATE ma_table SET contenu = '$contenu' WHERE...";
@mysql_query($sql);
}
?>

Le code présenté ici n’est pas sécurisé (pas de contrôle de la donnée de formulaire transmise), et il ne fonctionne pas car il n’est pas indiqué (clause WHERE) les modifications doivent être faites. Il est cependant très facile, en modifiant un peu le code JavaScript, de récupérer l’id du paragraphe et d’identifier ainsi la bonne ligne dans la base de données.


A Paris, le 18 avril 2010</p>