Prévisualisation dynamique d’articles (avec Ajax)

Ceci est une ARCHIVE, peut-être périmée. Vérifiez bien les compatibilités !

Comment afficher dans l’interface des rédacteurs le texte au fur et à mesure qu’il est entré dans le champs texte au clavier...

Principe de la contribution

Cette contribution nous a été demandée par des rédacteurs, qui, ne supportant pas de voir des accolades et des crochets dans leurs textes, ne trouvaient pas SPIP assez WYSIWYG... Il faut le reconnaître, cet aspect peut rebuter de nombreux utilisateurs lambdas voire bêtas parfois face à d’autres éditeurs, pour ne pas les citer, Dreamweaver ou FrontPage (arrgh).

Nous avons donc réalisé une petite prévisualisation dynamique (voire une pré-prévisualisation puisque la prévisualisation existe déjà après validation de l’article...). Le but étant de montrer ce que donne le texte SPIP dans une DIV lorsque le rédacteur relâche son clavier pendant une seconde.

Les objectifs étaient, en résumé :
-  afficher une prévisualisation du texte de l’article dans la page d’édition,
-  ne pas avoir besoin de valider un formulaire (et recharger la page) pour voir la prévisualisation,
-  intégrer cette prévisualisation dans le formulaire SPIP de manière aussi propre et aussi simple que possible,
-  permettre aux rédacteurs de cacher cette prévisualisation si elle les gêne.

Voici une capture pour vous montrer ce à quoi ça ressemble sur un SPIP 1.8.1... mais vu que c’est interactif vous ne le saurez vraiment qu’en l’essayant !

Capture
Capture de la prévisualisation Ajax

En bref, un éditeur WYSIWYG réalisé spécifiquement pour SPIP, simple et léger, qui plaira certainement aux rédacteurs en mal de visualisation. Il paraît que l’on travaille sur un SPIP qui intégrerait Ajax dans certains menus et formulaire pour plus d’interactivité (auquel cas je me ferais un plaisir d’adapter le code à d’éventuelles librairies Ajax).

Techniques mises en oeuvre

De manière simplifiée et pratique : tant que l’utilisateur tape ses touches clavier dans le champ « Texte », rien ne se passe. Lorsqu’il arrête de le faire pendant au moins une seconde, le bloc de visualisation est mis à jour (la première fois, il apparaît) juste en dessous du formulaire, qui lui montre le rendu du texte dans son navigateur.

Cette contribution est basée essentiellement sur Ajax, qui permet de faire une requête HTTP en Javascript de manière asynchrone, en envoyant le texte saisi dans le formulaire « Texte » de l’article puis en retirant le code HTML correspondant au texte dans lequel SPIP aura interprété les codes SPIP et de l’afficher dans une DIV (le HTML est donc interprété par le navigateur).

Un délai (une seconde par défaut) est inséré entre l’événement clavier et la requête HTTP, ainsi tant que l’utilisateur appuye sur les touches du clavier, l’affichage ne se met pas à jour. Lorsqu’il relâche son clavier, le résultat apparaît comme par magie en dessous de son formulaire ! Attention, cela ne vaut pas une validation et il faut toujours valider l’article sinon les modifications seront perdues.

Techniquement, l’événement « onkeypress » du textarea appelle la fonction Javascript « delayFunction », fonction générique dont le premier paramètre est une autre fonction Javascript, le second un délai. Cela permet d’attendre avant de mettre à jour la visualisation. A noter que lorsque que cette même fonction est appelée, elle annule le délai précédent et en crée un nouveau. D’où l’effet de temps-mort « tant qu’aucune touche n’est appuyée » avant de récupérer une prévisualisation.

La seconde fonction, délayée, effectue (à la fin du délai si vous avez suivi) une requête HTTP, sur une URL et en lui passant des paramètres. Lors de la réception de la réponse, le HTML reçu vient remplir une balise DIV identifiée. Les paramètres sont passés en POST. On lui fournit également des fonctions de callback appelées avant l’appel, au retour de l’appel et après insertion du code HTML reçu dans une DIV.

Installation de la contribution

Pour créer cette contribution, le fichier ecrire/articles_edit.php3 a été légèrement modifié, à partir d’un SPIP 1.8.1 (on peut l’écraser pour cette version). Pour les autres versions de SPIP, il suffit de rechercher les commentaires sous la forme :

// AJAX

Ces commentaires interviennent avant et après les balises ajoutées (une inclusion de librairie PHP3 un lien vers un fichier Javascript) et modifiées (le textarea qui permet d’entrer le texte de l’article) dans ce fichier.

Il suffit ensuite d’ajouter dans ce répertoire ecrire les fichiers :
-  ajax.js
-  article_preview.php3
-  inc_ajax_preview.php3

Puis écrivez un article, le résultat s’affiche en-dessous. Les tailles du textarea et de la prévisualisation s’ajustent lors de l’apparition de cette dernière. Enfin, comble du perfectionnement, lors de l’actualisation, les deux champs (textarea et div) scrollent au même endroit pour que la prévisualisation affiche effectivement le texte en train d’être édité (ceci dit, malheureusement, l’ajustement n’est pas parfait dans de nombreux cas) !

Fonctionnement de la librairie générique Ajax

La librairie Ajax se veut générique et peut-être utilisée pour d’autres mises à jour dynamiques, tant que l’on met à jour dynamiquement une balise DIV, en effectuant une requête HTTP sur une URL à laquelle on passe des variables. Etant générique, un fichier Javascript lui a été dédié, ainsi qu’une librairie PhP pour simplifier les appels délayés (qui nécessitent des échappements de quotes multiples).

La librairie PHP crée donc un code Javascript, que l’on placera en tant qu’un événement Javascript (onkeypress dans notre cas). Dans notre cas, le code placé est le suivant :

echo "<TEXTAREA id='text_area' NAME='texte'
 CLASS='formo' rows='$rows'
 COLS='40' wrap=soft";
echo 'onkeypress="'
 .formUpdateAjaxDelay('article_preview.php3',
 Array('text_area'), 'article_preview', 1, null, null,
 $onUpdateFunction)
 .'"';
echo ">$texte</TEXTAREA>\n";

Dans le fichier PhP de création du code Ajax (inc_ajax_preview), la fonction a la forme suivante :

formUpdateAjaxDelay($url, $fields, $div, $delay, $onCall, $onResult, $onUpdate)

Les paramètres sont :
-  $url : l’URL du fichier à appeler en HTTP,
-  $fields : tableau PHP des ids des éléments de formulaires à passer en paramètres, leurs noms et valeurs sont récupérées en Javascript pendant la construction de la requête,
-  $div : id du DIV à mettre à jour lorsque l’on reçoit la réponse,
-  $delay : délai à attendre avant d’envoyer la requête,
-  $onCall : code Javascript évalué juste avant l’appel HTTP,
-  $onResult : code Javascript évalué juste après le retour de la requête HTTP,
-  $onUpdate : code Javascript évalué après que le DIV ait été mis à jour.

Nous pouvons donc y associer trois textes Javascript, avant l’appel, au retour de l’appel et après avoir écrit le résultat dans la DIV. C’est du code Javascript évalué, vous pouvez donc y manipuler le DOM et y faire éventuellement des alertes pour tester les appels, les résultats Ajax. Ce code Javascript est pour PhP une string, faites attention aux quotes.

Pour note et comme exemple d’utilisation de notre fonction PhP, dans notre cas nous écrivons un code Javascript dans la variable $onUpdateFunction (cette variable est donc passée en paramètre de la fonction PhP formUpdateAjaxDelay), qui permet dans notre cas d’ajuster les tailles et le défilement des champs texte, elle est définie avant l’appel par le code suivant :

$onUpdate .= "var area = document.getElementById('text_area'); ";
$onUpdate .= "var previewText =
  document.getElementById('article_preview_text'); ";
$onUpdate .= "if(!area.newHeight){ ";
$onUpdate .= "  area.oldHeight = area.style.height; ";
$onUpdate .= "  area.newHeight =
  Math.floor(parseInt(area.style.height)/2)+'px'; ";
$onUpdate .= "  area.style.height = area.newHeight; ";
$onUpdate .= "} ";
$onUpdateFunction
  .="document.getElementById('article_preview')
  .style.display = 'block'; ";
$onUpdate .= "previewText.style.height = area.newHeight; ";
$onUpdate .= "previewText.scrollTop =
  parseInt(
    previewText.scrollHeight*area.scrollTop/area.scrollHeight
  ); ";

De même, après notre textarea (en dessous), vient l’encart de visualisation, caché par défaut, que l’on affiche lors de la réception des résultats. J’avoue le code est assez barbare avec beaucoup de fonctions Javascript mais il vous suffit de le recopier, (de préférence à partir du package distribué plus bas). Je le mets tout de même ici à titre d’exemple :

echo '<div id="article_preview_hide" style="display:
 block;"><a href="#text_area" onclick="var area =
 document.getElementById(\'text_area\');
 if(area.oldonkeypress) area.onkeypress =
 area.oldonkeypress; area.onkeypress();
 document.getElementById(\'article_preview_hide\').
 style.display = \'none\';">Afficher la
 prévisualisation</a></div>';
echo '<div id="article_preview" style="display: none;">';
echo '<div style="height: 10px;"></div>';
echo '<b>Pr&eacute;visualisation du texte <a
 href="#text_area" onclick="var area =
 document.getElementById(\'text_area\');
 area.oldonkeypress = area.onkeypress; area.onkeypress =
 null; area.style.height = area.oldHeight; area.newHeight =
 null; document.getElementById(\'article_preview\').
 style.display = \'none\'; ocument.getElementById
 (\'article_preview_hide\').style.display =
 \'block\';">(cacher la pr&eacute;visualisation)</a></b>
 <br />';
echo '<font style="color: #FF0000;"><i>Attention à bien
 valider votre texte, cette visualisation ne modifie pas
 l\'article</i></font>';
echo '<table class="formo"  width="100%" cellpadding="0"
 cellspacing="0" border="0"><tr class="spip_barre"><td>';
echo '<div id="article_preview_text" $dir_lang
 style="font-size: small; overflow: auto;">';
echo '</div>';
echo '</td></tr></table>';
echo '</div>';

En conclusion

Voilà, Ajax tellement vanté (ou décrié, selon) par les programmeurs Web est en fait relativement simple à mettre en oeuvre. Il faut juste ne pas avoir peur d’utiliser Javascript massivement (Google le fait pour ses maps et son mail) et oser manipuler le DOM (Document Object Model) qui est maintenant bien défini et standardisé).

Bien sûr, je suis à votre disposition pour toute info complémentaire et surtout pour perfectionner deux trois aspects de la contribution (notamment le scroll du textarea et du div en fonction de la position du curseur dans le textarea... ou la synchronisation des deux scrolls...).

Attention, au risque de me répéter, la prévisualisation ne modifie pas l’article et il faut bien valider le formulaire pour que les modifications soient prises en compte.

Discussion

Aucune discussion

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom