Création d'un éditeur wysiwyg

WYSIWYG Editor
Ce tutoriel à pour but de montrer comment créer un éditeur riche de type WYSIWYG (WhatYouSeeIsWhatYouGet)

Création de l'éditeur:
Pour activer le mode édition, il existe la propriété "ContentEditable".

Pour voir toutes les informations sur cet attribut.

Notre éditeur sera une balise DIV. Son id sera « ortf » afin de pouvoir l’appeler durant les différents scripts.

Structure de notre page :

<html>
<head>
</head>
<body>
<div style="height: 377px" id="ortf" contenteditable="true">
</div>
</body>
</html>

Création de la Toolbar:

Design:

Un éditeur doit contenir une toolbar qui elle-même contiendra différents boutons pour mettre en forme le texte.

Nous utiliserons le CSS & JavaScript afin de le rendre dynamique.
Pour faire simple, créons un tableau à 3 lignes, avec aucune marge. Rajoutons un tableau dans chaque ligne sans attributs particuliers.
Normalement, nous devrions tomber là dessus :

<table style="border-style: outset; border-width: 2px; background-color: #C0C0C0;" cellpadding="0" cellspacing="0">
<tr>
<td>
<table>
<tr>
<td> </td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table>
<tr>
<td> </td>
</tr>
</table>
</td>
</tr>
<tr>
<tr>
<td>
<table>
<tr>
<td> </td>
</tr>
</table>
</td>
</tr>
<tr>
</table>

Le style du tableau principal est en 3D, avec un bord de 2px de couleur grise.

Chaque cellule des tableaux intermédiaires contiendront les boutons de mise en forme du texte.
Pour donner un effet de style, il faudrait que les boutons changent de couleur lors du passage de la souris.
Ainsi donc, il faudrait faire un script sur les événements « OnMouseOver » (Souris dessus) et « OnMouseOut » (Souris sortie).
Les fonctions doivent avoir comme argument la cellule qui les appelle. Nous mettrons donc comme argument l’objet « this »

<script language="javascript" type="text/javascript">
// Curseur sur la cellule
function btn_on(obj){
obj.style.background="#99CCFF";
obj.style.border="1px solid #808080";
}
// Le curseur quitte la cellule
function btn_off(obj){
obj.style.background="#C0C0C0";
obj.style.border="1px solid #C0C0C0";
}
</script>
[... *
<td style="padding: 2px; cursor: pointer; border: 1px solid #C0C0C0; background-color: #C0C0C0;" onmouseout="btn_off(this)" onmouseover="btn_on(this)">

Le style de la cellule passé par l’attribut « Style » est le style par défaut. C’est celui qui sera restitué par la fonction « btn_off() ».

Script:
Pour interagir avec le Div éditable, il existe la fonction « ExecCommand ».
Pour l’utiliser, il faut l’appeler par l’intermédiaire du document du Div.

Cette fonction possède 3 arguments. La première, cmdID, est le nom de la commande à effectuer.
Les deux autres sont facultatives. Nous reviendrons dessus plus tard.
Récapitulatifs des commandes basiques: (Pour une liste plus exhaustive).

cmdID Description
Bold Gras
Italic Italique
Underline Souligné
StrikeThrough Barré
JustifyLeft Aligné à gauche
JustifyRight Aligné à droite
JustifyCenter Centrer
JustifyFull Justifier
InsertUnOrderedList Liste à puce
InsertOrderedList Liste chiffrée

Afin de centraliser les commandes, nous allons créer une fonction, la fonction « formatage ».
Elle aura pour argument le cmdID à appliquer au texte, et un autre argument que nous utiliserons plus tard.

function formatage(action,autre){
var ob = document.getElementById("ortf");
ob.document.execCommand(action,false,autre);
}

Ajouter donc à chaque cellule l’attribut « OnClick="formatage(‘cmdID’,’’) ;" », ou cmdID fait référence à une commande du tableau précédent.

Il faut maintenant pouvoir choisir la police ou la taille du texte.
Pour ce faire, il nous faut créer 2 dropdowns. Un nommé « cmbpolice » et un « cmbtaille ».
Remplir le premier avec différents noms de police, et le deuxième avec des chiffres allant de 1 à 7.

L’application d’une police se fait avec la commande « FontName ». Le nom de la police est passé dans le 3eme argument de ExecCommand, soit dans le 2eme argument de notre fonction.
Ainsi donc, dans l’événement OnChange, il faut appliquer la commande FontName et la valeur du dropdown.
Il en va de même avec la taille de la police, où la commande est FontSize.

<select name="cmbpolice" onchange="formatage('FontName',this.value)">
<option selected="">Police</option>
<option value="Arial">Arial</option>
<option value="Verdana">Verdana</option>
<option value="Courier New">Courier New</option>
<option value="Time New Roman">Time New Roman</option>
<option value="Comic Sans MS">Comic Sans MS</option>
</select>
<select name="cmbtaille" onchange="formatage('FontSize',this.value)">
<option selected="">Taille</option>
<option value="1">1 (petite)</option>
<option value="2">2</option>
<option value="3">3 (normale)</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7 (grande)</option>
</select>

Pour ce qui est de la couleur du texte, rien de bien compliqué !
Il suffit de faire un pop-up avec un sélecteur de couleur. Sauf que le bouton pour valider appel la fonction de l’opener, avec comme commande soit « FontColor » pour la couleur du texte, ou « BackColor » pour le sur lignage du texte, avec bien sure en 2eme argument la couleur au format hexadécimal.
(Pour ce qui ne verrait pas : opener.formatage("FontColor",CouleurSelectionée") ;)

Travailler avec des objets:
Nous avons vu l’essentiel du formatage.
Maintenant, il est intéressant de s’attaquer aux objets. Mais, que sont les objets ? Ben, les images, les formulaires, …

Pour les insérer, vous avez bien sure des commandes déjà toutes prêtes. Mais, comment faire lorsque l’on veut que ces objets aient des attributs spécifiques ?
Et bien, il va falloir utiliser les textRanges.
Les textRanges sont des fonctions qui marchent avec la sélection du texte.
Par exemple, la charnière de notre script pour les objets sera : var range = document.selection.createRange();.
Nous travaillerons ensuite avec l’objet range. Plus particulièrement avec la fonction pasteHTML et la propriété htmlText.

pasteHTML colle du texte à l’endroit ou se trouve le curseur ; htmlText retourne le texte sélectionné.

Ainsi, pour insérer une image, il faudra faire range.pasteHTML("<img src='mon_image.png'>") ;
Mais, pourquoi ne pas utiliser la fonction de base ?
Tout simplement parce que si je veux ouvrir un pop-up qui permet de paramétré tous les attributs de l'image, et bien, j'ai un accès direct à ce que je vais insérer.
Si vous avez par exemple des cadres prédéfinis et que vous voulez en entourer le texte sélectionné, et bien il suffira de faire range.pasteHTML("<balise aa='bb' cc='dd'>" + range.htmlText + "</balise>") ;Nos fonctions aurons donc cette allure si vous avez bien suivit ^^

function encadrer(b1,b2){
var ob = document.getElementById("ortf");
var range = ob.document.selection.createRange();
range.pasteHTML(b1 + range.htmlText + b2);
}
function ajouter_objet(objet){
var ob = document.getElementById("ortf");
var range = ob.document.selection.createRange();
range.pasteHTML(objet);
}

Poussons le bouchon plus loin:
Un truc assez sympathique à faire, c'est de savoir si le texte ou le curseur se trouve est en gras ou non. (Ou dans d'autres états bien sure).
Si c'est le cas, et bien hop ! On met le bouton « Gras » d'une couleur différente affin de montrer qu'il est actif.

Pour réaliser ceci, il faut utiliser la fonction queryCommandValue.
Cette fonction retourne false ou true, et n'accepte qu'un seul argument : celui de la cmdID à vérifier.
Il faut créer une fonction sans argument qui testera tous les styles souhaité (Gras, Italique, Souligné,...) et de traiter le bouton correspondant par la suite.
Petit retour en arrière : Il faut pour cela nommé avec l'attribut « id » les boutons correspondant. Ainsi, pour le bouton Gras, id="btn_bold", pour l'italique, id="btn_italic".

La fonction regarde le style, si true, alors btn_on(document.getElementById("act_"+cmdID_testé));.

On peut ainsi rendre plus dynamique et plus agréable notre éditeur.

function tester(){
var ob = document.getElementById("ortf").document;
if(ob.queryCommandValue("Bold")){
btn_on(document.getElementById("act_bold"));
}
// Rajouter de même toutes les commandes à tester
}

Il faut appeler cette fonction avec les évènements onclick & onkeydown du Div.

Oups !
Si vous appuyé sur entré et que vous dépassé le cadre du div, vous verrez celui-ci s'agrandir :(
Pour éviter ce petit « désagrément », il faut rajouter un objet de style au div : l'objet overflow:scroll.

Ainsi, quand le texte dépassera la zone, il mettra des scroll bars au lieu de nous faire un petit auto-resize.

Les positions :
Rassurez-vous, pas le Kâma-Sûtra ! (Pour les coquins, www.kamasutra.fr/ ^^)

Une autre commande toute bête : `AbsolutePosition'. Met en position absolue l'objet sélectionné.
Mais, pour que cette fonction soit optimale, il faut rajouter dans une fonction d'initialisation la commande `2D-Position' : permet le déplacement par tiré-déplacé.

Un petit peu plus loin:
Bon, si vous n'êtes pas perdu dans mes expliquassions quelque peut farfelus, on va passer à une autre étape : les modifications directes.

Ceci permet de modifier « en Live » les attributs de l'objet sélectionné.
Par exemple, pour rajouter/modifier des objets CSS à un objet.

Pour ce faire, il faut utiliser l'objet « document.ActiveElement », et, choisir les caractéristiques à changer.
Après, à vous de créer une fonction qui par l'intermédiaire d'un pop-up va configurer comme vous le souhaité votre objet.

And to finish:
Pour finir, il est en général utile de récupérer le texte édité.
Pour le récupérer, rien de plus simple !

function getHTML(){
var ob = document.getElementById("ortf").document;
retun ob.innerHTML;
}

J'en ai finis avec mon tutoriel ; j'espère qu'il vous a plut !

Si jamais vous avez des questions, n'hésitez pas !

MrReivax

A voir également
Ce document intitulé « Création d'un éditeur wysiwyg » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous