Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
ACCUEIL JAVASCRIPT FORUM JAVASCRIPT F.A.Q JAVASCRIPT TUTORIELS JAVASCRIPTS SOURCES JAVASCRIPT LIVRES AJAX

Modification "inline" de données avec AJAX

Date de publication : 15/08/06

Par Olivier Lance (Accueil)
 

Ce tutoriel a pour but de vous montrer comment mettre en oeuvre simplement un script de modification "inline" de vos données affichées dans une page web.

Introduction
I. Première partie : Création du script "simple"
I-1. Analyse préliminaire
I-2. Côté client
I-2-a. La page web
I-2-b. Le Javascript
I-2-b-i. Mode d'édition
I-2-b-ii. Sauvegarde
I-3. Côté serveur
II. Deuxième partie : Généralisation du script, emploi de classes
II-1. Les modifications apportées
II-1-a. Limites du script actuel
II-1-b. Pourquoi des classes ?
II-2. Adaptation du code d'origine
II-2-a. Réorganisation des fichiers
II-2-b. Modification de index.php
II-2-c. Fonctionnalités des classes
II-2-d. Modification d'inlinemod.js
II-2-d-i. La fonction inlineMod
II-2-d-ii. La fonction sauverMod
II-2-e. Modification de sauverMod.php
II-3. Implémentation des classes
II-3-a. L'objet texte
II-3-b. L'objet nombre
II-3-c. L'objet texteMulti
Conclusion
Liens
Addenda
Constantes utilisées pour les accès BDD


Introduction

De plus en plus, la "mode" pousse les développeurs à créer des pages web dynamiques et interactives construites pour un confort d'utilisation toujours augmenté pour l'utilisateur final.
Aujourd'hui ce confort passe, entr'autres, par l'emploi du Javascript et de l'objet XMLHTTPRequest, qui permet d'effectuer des requêtes vers le serveur web de manière asynchrone. Couplé avec quelques scripts PHP, il permet de mettre à jour des informations au sein d'une page sans en recharger l'intégralité du contenu.

C'est cette méthode que je vous propose d'utiliser pour mettre en place un système de modification inline de données dans une page web.
Par modification inline, j'entends modification d'éléments distincts de la page, directement à leur emplacement d'origine.

Pour bien vous rendre compte de l'idée, vous pouvez d'ores et déjà trouver ici un exemple fonctionnel du résultat de ce tutoriel. L'utilisation est simple : en double-cliquant sur une donnée du tableau, vous entrez en mode d'édition. Vous pouvez alors changer la valeur de la donnée, puis valider votre saisie en appuyant sur Entrée ou en cliquant à l'extérieur du champ de texte.
Actualisez, la valeur que vous avez entrée est sauvegardée !

Ce tutoriel est découpé en deux parties : la première partie vous guidera et vous expliquera les étapes de création de ce script d'édition. La seconde partie, pour les plus chevronné(e)s, reprendra le code de la première partie pour le généraliser et permettre une plus grande flexibilité d'implémentation grâce à l'utilisation de classes.

Dans tout le tutoriel, je considèrerai que vous êtes à l'aise avec l'utilisation de l'objet XMLHTTPRequest et avec tout ce qui concerne les appels de requêtes MySQL à partir de PHP, de leur création à l'exploitation de leur résultat.

warning Depuis un moment, mon script comprenait une erreur qui empêchait l'enregistrement dans la table des modifications apportées par l'utilisateur.
Je tiens à m'excuser pour ce problème et le temps que j'ai pris à le résoudre. Je vous propose de télécharger ce zip qui contient une version des fichiers qui fonctionne correctement en local sur ma machine.
(en cas de problème avec le lien précédent : miroir)

I. Première partie : Création du script "simple"


I-1. Analyse préliminaire

Comme vous avez pu le voir dans la page donnée à l'introduction, l'idée est simple : lors d'un double-click sur l'une des cellules du tableau, son contenu est remplacé par un champ de saisie qui prend pour valeur le texte de la cellule.
Le double-click permet donc de passer d'un mode d'affichage à un mode d'édition.

Dans ce mode d'édition, la valeur affectée est librement modifiable, puis enregistrée soit en appuyant sur la touche Entrée, soit en sortant du champ de saisie.

De ces simples constats on peut donc tirer l'analyse descendante suivante :

Analyse générale
Analyse générale


L'affichage des données se fait dans un premier temps grâce à la page web dont le code sera présenté peu après. Lors du retour vers le mode d'affichage après la sauvegarde des données, nous devrons user d'un peu de Javascript afin de supprimer le champ de saisie et de remettre le texte qu'il contenait dans la cellule.

Le passage en mode d'édition peut être découpé en plusieurs actions principales :

Analyse du mode d'édition
Analyse du mode d'édition


Dans un premier temps, avant de remplacer le contenu de la cellule, il faut en garder une copie pour pouvoir l'assigner au contenu du champ de saisie.
Ensuite, le champ de saisie est créé. Avant de l'afficher, il conviendra de modifier quelques unes de ses propriétés : sa taille, son style CSS...
Et enfin, une fois le champ affiché, on sélectionne son contenu et on lui donne le focus pour que l'édition puisse être immédiatement effectuée au clavier.

Selon le type de valeur à modifier (texte, texte "long" pouvant s'étendre sur plusieurs lignes, nombre...), nous introduirons un comportement différent. Pour ce tutoriel, les textes et nombres seront modifiés grâce à un champ de saisie classique (balise input) et les textes longs seront modifiés grâce à une zone de texte multilignes (balise textarea). Il faudra bien sûr, à un moment ou un autre, spécifier quel est le type de la donnée affichée.

De même, la phase de sauvegarde peut être ainsi découpée :

Analyse de la sauvegarde
Analyse de la sauvegarde


Cette phase est relativement simple. Une fois l'objet XMLHTTPRequest créé, nous appelons un script PHP en lui passant en paramètres les valeurs à sauver, puis nous sortons du mode d'édition une fois la sauvegarde effectuée.
Afin de garder un script relativement général, nous ne différencierons pas la requête selon le type du champ modifié, ou bien selon le nom du champ correspondant dans la base de données (ce qui reviendrait à faire une requête par champ). Nous passerons donc en paramètres au script le nom du champ dans la base de données, son type, sa valeur et bien sûr l'id de l'enregistrement dont il faut modifier le champ.

Comme vous pouvez le voir dans le diagramme précédent, nous ne ferons pas de gestion d'erreur de la sauvegarde dans cette première partie. Je considère que vous savez utiliser l'objet XMLHTTPRequest et ses propriétés pour arriver à vos fins sur ce plan.

La sortie du mode d'édition se fait en deux étapes principales : remplacement du champ de saisie par son contenu dans la cellule en cours d'édition, puis suppression du champ.


Nous avons dorénavant en main tous les élements pour passer à la réalisation des différents codes qui permettront de donner corps à ce système d'édition inline.


I-2. Côté client

La page web et le script PHP (côté serveur) qui seront utilisés sont bien sûr spécifiques à l'exemple que j'entends traiter dans ce tutoriel. Avant toute chose, il me semble donc judicieux de donner dès maintenant la structure de la table qui contiendra les données utilisées. Il s'agit d'une simple table recensant les états civils d'utilisateurs fictifs :

CREATE TABLE `inlinemod` (
  `id` 			int(11) NOT NULL auto_increment,
  `nom` 		varchar(255) NOT NULL default '',
  `prenom` 		varchar(255) NOT NULL default '',
  `adresse`		tinytext NOT NULL,
  `code_postal`		varchar(5) NOT NULL default '',
  `ville` 		varchar(255) NOT NULL default '',
  `enfants`		int(11) NOT NULL default '0',
  `email` 		varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`)
)
Dans cette table, tous les champs affichés et modifiables sont donc de type texte, à l'exception du champ adresse qui sera de type texte-multi et du champ enfants qui sera de type nombre.


I-2-a. La page web

Le code de la page web de présentation des données est des plus basiques : une connexion à la base pour récupérer les données à afficher, puis une boucle afin de construire le tableau contenant celles-ci. Voici déjà le code complet pour une vue d'ensemble. Nous nous concentrerons ensuite sur les détails importants.

<?php
// Connexion à la base de données
mysql_connect(DB_HOST, DB_USER, DB_PASSWORD) or die(mysql_error());
mysql_select_db(DB_NAME) or die(mysql_error());

$sql = 'SELECT * FROM `'.DB_TABLE_NAME.'`';
$result = mysql_query($sql) or die(__LINE__.mysql_error().$sql);

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1" />

    <title>Modification "inline" de données grâce à XMLHTTPRequest</title>

    <link rel="StyleSheet" type="text/css" href="index.css"/>
    <script type="text/javascript" src="inlinemod.js"></script>
</head>

<body>
    <h1>Utilisateurs</h1>


    <table id="table-utilisateurs">
        <tr>
            <th>Nom</th>
            <th>Prénom</th>
            <th>Adresse</th>
            <th>Code Postal</th>
            <th>Ville</th>
            <th>Enfants</th>
            <th>Email</th>
        </tr>

        <?php
        while($user = mysql_fetch_assoc($result))
        {
        ?>
            <tr>
                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'nom', 'texte')">
                    <?php echo $user['nom']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'prenom', 'texte')">
                    <?php echo $user['prenom']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'adresse', 'texte-multi')">
                    <?php echo $user['adresse']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'code_postal', 'texte')">
                    <?php echo $user['code_postal']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'ville', 'texte')">
                    <?php echo $user['ville']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'enfants', 'nombre')">
                    <?php echo $user['enfants']; ?>
                </td>

                <td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'email', 'texte')">
                    <?php echo $user['email']; ?>
                </td>
            </tr>
        <?php
        }
        ?>
    </table>

</body>
</html>

<?php

	mysql_close();

?>
Pour votre propre code vous aurez bien évidemment à définir les variables de connexion à la base de données, mais là n'est pas notre sujet.
En premier lieu on remarque l'inclusion du fichier inlinemod.js, qui contiendra les fonctions utilisées pour le mode d'édition et la sauvegarde.

Le plus important se situe au niveau des cellules du tableau, dont nous allons détailler les attributs. Pour référence voici déjà une copie de la la balise d'ouverture de la première cellule :

<td class="cellule" ondblclick="inlineMod(<?php echo $user['id']; ?>, this, 'nom', 'texte')">
L'attribut class ne fait qu'assigner à la cellule une classe CSS que voici :

td.cellule {
	text-align: center;
	border: 1px solid #376ef9;
	
	cursor: pointer;
}
La modification de l'apparence du curseur sur les cellules permet de signifier de manière simple à l'utilisateur qu'une action est ici possible.

L'attribut ondblclick nous plonge plus en avant dans le sujet puisqu'il est le point d'entrée vers le mode d'édition, grâce à la fonction inlineMod. Celle-ci prend quatre paramètres :

  1. L'id de l'enregistrement dans la base de données, afin de savoir quoi modifier lors de l'appel du script PHP
  2. Une référence sur l'objet qui contient la valeur à modifier. Ici, this est passé pour désigner la balise td
  3. Le nom du champ à modifier dans la base de données, toujours pour renseigner le script PHP
  4. Le type de la valeur. Ici elle est de type texte, plus bas dans la page vous trouverez également un type texte-multi et un type nombre
Voyons maintenant ce que donne, justement, l'implémentation de cette fonction inlineMod.


I-2-b. Le Javascript


I-2-b-i. Mode d'édition

Le code que je vais vous présenter ici ne respecte pas exactement l'ordre de l'analyse présentée ci-dessus. L'esprit est le même bien sûr, mais le mode de fonctionnement du Javascript et notamment les possibilités offertes par la manipulation du DOM permettent de regrouper certaines étapes.

Avant toute chose, afin qu'une seule édition ne soit effectuée à la fois, nous allons introduire une variable globale de type booléen qui nous permettra de valider ou non le passage au mode d'édition suivant qu'une édition est déjà en cours. Un test sur cette variable en début de fonction permettra ce contrôle :

//On ne pourra éditer qu'une valeur à la fois
var editionEnCours = false;

//Fonction de modification inline de l'élément double-cliqué
function inlineMod(id, obj, nomValeur, type)
{
	if(editionEnCours)
	{
		return false;
	}
	else
	{
		editionEnCours = true;
	}
Si la fonction n'est pas stoppée, nous pouvons alors créer notre champ de saisie en fonction du type de la valeur à modifier :

	//Objet servant à l'édition de la valeur dans la page
	var input = null;

	//On crée un composant différent selon le type de la valeur à modifier
	switch(type)
	{
		//Valeur de type texte ou nombre
		case "texte":
		case "nombre":
			input = document.createElement("input");
			break;

		//Valeur de type texte multilignes
		case  "texte-multi":
			input = document.createElement("textarea");
			break;
	}
Comme annoncé précédemment nous créons, grâce au DOM, une balise input pour les types texte et nombre, et une balise textarea pour le type texte-multi.

L'élément créé peut ensuite être manipulé comme nous le désirons. Nous allons affecter le texte à éditer à sa propriété value puis adapter sa taille à la largeur de ce texte :

	//Assignation de la valeur
	if (obj.innerText)
		input.value = obj.innerText;
	else
		input.value = obj.textContent;
		
	input.value = trim(input.value);
	
	//On lui donne une taille un peu plus large que le texte à modifier
	input.style.width  = getTextWidth(input.value) + 30 + "px";	
Dans value est placé le contenu sous forme de texte de l'objet parent. Par souci de compatibilité, un test est effectué pour savoir qui de innerText (Internet Explorer, Opera, Safari, Konqueror) ou textContent (Firefox, ...) doit être utilisé. Comme Firefox renvoie également les sauts de lignes et espaces présents dans la balise dont on appelle textContent, une fonction trim est utilisée pour supprimer ceux-ci. Son implémentation est donnée dans le prochain extrait de code.

Afin d'adapter la taille du champ de saisie à son contenu, la fonction getTextWidth est utilisée. Il s'agit d'une petite astuce utilisant le DOM et la propriété offsetWidth pour "mesurer" la taille d'un texte placé dans une balise span :

//Suppression des espaces/sauts de ligne inutiles (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256C0C0062AC78)
function trim(value) {
   var temp = value;
   var obj = /^(\s*)([\W\w]*)(\b\s*$)/;
   if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }
   var obj = /  /g;
   while (temp.match(obj)) { temp = temp.replace(obj, " "); }
   return temp;
}


//Fonction donnant la largeur en pixels du texte donné (merci SpaceFrog !)
function getTextWidth(texte)
{
	//Valeur par défaut : 150 pixels
	var largeur = 150;

	if(trim(texte) == "")
	{
		return largeur;
	}

	//Création d'un span caché que l'on "mesurera"
	var span = document.createElement("span");
	span.style.visibility = "hidden";
	span.style.position = "absolute";

	//Ajout du texte dans le span puis du span dans le corps de la page
	span.appendChild(document.createTextNode(texte));
	document.getElementsByTagName("body")[0].appendChild(span);

	//Largeur du texte
	largeur = span.offsetWidth;

	//Suppression du span
	document.getElementsByTagName("body")[0].removeChild(span);
	span = null;

	return largeur;
}
Les commentaires du code devraient suffire à décrire cette fonction qui n'est pas d'une difficulté particulière. Une fois les propriétés de notre champ ajustées, nous pouvons l'afficher dans la cellule, sélectionner son contenu et lui donner le focus :

	//Remplacement du texte par notre objet input
	obj.replaceChild(input, obj.firstChild);

	//On donne le focus à l'input et on sélectionne le texte qu'il contient
	input.focus();
	input.select();
Il reste maintenant à définir les événements qui déclencheront la sauvegarde de la saisie. La sortie du champ sera détectée grâce à l'événement onblur, tandis que l'appui sur la touche Entrée sera vérifié grâce à l'événement onkeydown et un test sur la touche appuyée lorsque l'événement est déclenché.

	//Sortie de l'input
	input.onblur = function sortir()
	{
		sauverMod(id, obj, nomValeur, input.value, type);
		delete input;
	};

	//Appui sur la touche Entrée
	input.onkeydown = function keyDown(event)
	{
        if (!event&&window.event)
        {
            event = window.event;
        }
		if(getKeyCode(event) == 13)
        {
			sauverMod(id, obj, nomValeur, input.value, type);
			delete input;
		}
	};
Pour la compatibilité, quelques tests s'imposent sur la propriété event. L'important est la comparaison avec le code caractère 13 qui représente le saut de ligne, et qui nous prévient donc d'un appui sur la touche Entrée.
La fonction getKeyCode renvoie ce code de caractère à partir de la propriété event :

//Fonction renvoyant le code de la touche appuyée lors d'un événement clavier
function getKeyCode(evenement)
{
    for (prop in evenement)
    {
        if(prop == 'which')
        {
            return evenement.which;
        }
    }

    return evenement.keyCode;
}
La fonction inlineMod est maintenant terminée. Son fonctionnement correspond à l'analyse que nous en avions fait en première partie, et il reste maintenant à implémenter la fonction de sauvegarde, sauverMod.

Cependant, vous l'avez peut-être déjà deviné, il existe un petit problème dans notre code. Après la sauvegarde, le champ de saisie est supprimé. Si le champ possédait encore le focus à cet instant, cela causera donc le déclenchement de l'événement onblur. Ainsi, si la sauvegarde est provoquée par l'appui sur la touche Entrée, la fonction sauverMod sera appelée deux fois.
Pour pallier ce problème, nous allons introduire une seconde variable d'état qui marchera tout comme editionEnCours pour vérifier que nous sommes déjà passés ou non par la fonction de sauvegarde.

Le code final de notre fonction inlineMod est donc :
Fonction inlineMod

//On ne pourra éditer qu'une valeur à la fois
var editionEnCours = false;

//variable évitant une seconde sauvegarde lors de la suppression de l'input
var sauve = false;

//Fonction de modification inline de l'élément double-cliqué
function inlineMod(id, obj, nomValeur, type)
{
	if(editionEnCours)
	{
		return false;
	}
	else
	{
		editionEnCours = true;
		sauve = false;
	}

	//Objet servant à l'édition de la valeur dans la page
	var input = null;

	//On crée un composant différent selon le type de la valeur à modifier
	switch(type)
	{
		//Valeur de type texte ou nombre
		case "texte":
		case "nombre":
			input = document.createElement("input");
			break;

		//Valeur de type texte multilignes
		case  "texte-multi":
			input = document.createElement("textarea");
			break;
	}

	//Assignation de la valeur
	if (obj.innerText)
		input.value = obj.innerText;
	else
		input.value = obj.textContent;
		
	input.value = trim(input.value);

	//On lui donne une taille un peu plus large que le texte à modifier
	input.style.width  = getTextWidth(input.value) + 30 + "px";

	//Remplacement du texte par notre objet input
	obj.replaceChild(input, obj.firstChild);

	//On donne le focus à l'input et on sélectionne le texte qu'il contient
	input.focus();
	input.select();

	//Assignation des deux événements qui déclencheront la sauvegarde de la valeur

	//Sortie de l'input
	input.onblur = function sortir()
	{
		sauverMod(id, obj, nomValeur, input.value, type);
		delete input;
	};

	//Appui sur la touche Entrée
	input.onkeydown = function keyDown(event)
	{
        if (!event&&window.event)
        {
            event = window.event;
        }
		if(getKeyCode(event) == 13)
        {
			sauverMod(id, obj, nomValeur, input.value, type);
			delete input;
		}
	};
}
Tout est maintenant prêt pour l'implémentation de la fonction sauverMod.


I-2-b-ii. Sauvegarde

Notre fonction de sauvegarde s'articule autour de l'objet XMLHTTPRequest. Il convient donc de commencer par sa création. Pour cela nous allons utiliser une fonction, getXMLHTTP, qui nous renverra une instance de l'objet selon le navigateur utilisé.

// retourne un objet xmlHttpRequest.
// méthode compatible entre tous les navigateurs (IE/Firefox/Opera)
function getXMLHTTP()
{
    var xhr = null;
    if(window.XMLHttpRequest)
    { // Firefox et autres
        xhr = new XMLHttpRequest();
    }
    else if(window.ActiveXObject)
    { // Internet Explorer
        try
        {
            xhr = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch(e)
        {
            try
            {
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(e1)
            {
                xhr = null;
            }
        }
    }
    else
    { // XMLHttpRequest non supporté par le navigateur
        alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
    }

    return xhr;
}
Je ne commenterai pas plus cette fonction. Elle est directement tirée du tutoriel de Denis Cabasson, un autocomplétion pas à pas, que je ne peux que vous conseiller de lire ! (Voyez également les autres liens en bas de page)

Voici comment nous allons créer notre objet :

//Objet XMLHTTPRequest
var XHR = null;

//Fonction de sauvegarde des modifications apportées
function sauverMod(id, obj, nomValeur, valeur, type)
{
	//Si on a déjà sauvé la valeur en cours, on sort
	if(sauve)
	{
		return false;
	}
	else
	{
		sauve = true;
	}

	//Si l'objet existe déjà on abandonne la requête et on le supprime
	if(XHR && XHR.readyState != 0)
	{
		XHR.abort();
		delete XHR;
	}

	//Création de l'objet XMLHTTPRequest
	XHR = getXMLHTTP();

	if(!XHR)
	{
		return false;
	}
Tout le code ne concerne pas directement la création de notre objet. Le premier bloc if, vous l'aurez compris, permet d'invalider un appel à la fonction de sauvegarde si celle-ci a déjà été appelée pour la même phase d'édition.

XHR est déclaré comme une variable globale à laquelle nous assignons le résultat de getXMLHTTP. Avant cette assignation, nous vérifions par sécurité que l'objet n'est pas déjà créé et en cours de transaction avec le serveur. Le cas échéant, la connexion est tout simplement coupée et l'objet détruit avant d'être recréé.

En suivant l'analyse effectuée en première partie, il reste donc à envoyer la requête vers le script PHP et à sortir du mode d'édition. Cela se fait de la manière suivante :

	//URL du script de sauvegarde auquel on passe la valeur à modifier
	XHR.open("GET", "sauverMod.php?id=" + id + "&champ=" + nomValeur + "&valeur=" + escape(valeur) + "&type=" + type + ieTrick(), true);

	//On se sert de l'événement OnReadyStateChange pour supprimer l'input et le replacer par son contenu
	XHR.onreadystatechange = function()
	{
		//Si le chargement est terminé
		if (XHR.readyState == 4)
		{
			//Réinitialisation de la variable d'état d'édition
			editionEnCours = false;

			//Remplacement de l'input par le texte qu'il contient
			obj.replaceChild(document.createTextNode(valeur), obj.firstChild);
		}
	}

	//Envoi de la requête
	XHR.send(null);
Le script est appelé avec les paramètres déjà annoncés : l'id de l'enregistrement à modifier, le nom du champ édité dans cet enregistrement, la valeur que celui-ci doit prendre et le type de cette valeur.

Le retour en mode affichage se fait dans l'événement onreadystatechange de XHR. Si l'appel du script PHP s'est bien passé, et donc si readyState vaut 4, la variable editionEnCours est réinitialisée (sauve l'étant au début de la fonction), et le contenu de l'objet parent du texte édité est remplacé grâce au DOM.