Prévisualisation dynamique d’articles (avec Ajax)

All contributions published for previous SPIP versions

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
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.

updated on 17 November 2005

Discussion

5 discussions

  • 2

    Du nouveau pour SPIP 1.9.1 ?

    J’ai essayé de l’intégrer à la Bare typo Enrichie, mais trop de choses ont changé.

    D’autre part, SPIP semble se diriger vers un usage généralisé de jquery. Y as-tu pensé ?

    Reply to this message

  • Super! c’est pratique c’est simple et ça marche bien. Loin des éditeurs compliqués, ça semble vraiment la solution pour améliorer l’ergonomie et l’édition pour les auteurs. Je vais tenter de rajouter deux petites fonctions qui me semblerais pas du luxe: la taille et les couleurs. Pour ma part je trouverais cela largement suffisant pour tous les usages. Depuis un dizaines de sites sous spip que j’ai installé, on m’a demandé une seule fois comment faire un tableau, et les raccourcis images et doc sont trés pratique, surtout avec les modéles, de mon point de vue c’est encore mieux qu’une intégration par wysiwyg, plus propre et fiable et surtout plus souple. En bref cet outil plus les tailles et les couleurs et c’est l’édition sans limites. Bravo!

    Reply to this message

  • Hélas, trois fois hélas, ta super contrib’ semble ne plus fonctionner avec la version 1.8.3 de Spip !

    Je n’ai pas trouvé (encore du moins) d’où venait le bug, mais il se manifeste ainsi: la prévisualisation ne s’affiche pas du tout !

    Reply to this message

  • ca ne marche plus avec la dernière svn

    le code d’article_edit.php commence maintenant comme ceci

    if (!defined(“_ECRIRE_INC_VERSION”)) return;

    include_ecrire(“inc_presentation”);
    include_ecrire(“inc_rubriques”);
    include_ecrire (“inc_documents”);
    include_ecrire (“inc_barre”);
    // AJAX

    include_ecrire (“inc_ajax_preview.php3”);
    // AJAX

    si ca pouvait remarcher.... car c’est vraiment une aide appréciable .

    le mettre en plugin doit etre possible

    Reply to this message

  • 1

    Merci pour cette contrib qui va satisfaire quelques “olibrius” autour de moi.
    Par contre il faut penser à renomer le fichier de ta contribution article_edit.php3 en articles_edit.php3 (manque le “s” à artcile), car il ne s’écrase pas sinon. Mais c’est juste un détail, qui peut avoir son importance pour quelques uns d’entres-nous ! Sinon cela fonctionne très bien sous Mozilla Firefox 1.0.7.

    Merci encore et bonne route...

    • Merci pour ce premier message, ça fait plaisir de voir que ma petite contribution peut servir à faciliter la rédaction d’olibrius ou autres .
      Je vais corriger la version en ligne à propos du nom de fichier, n’oubliez cependant pas qu’il vaut mieux patcher manuellement le fichier pour les versions de SPIP autres que la 1.8.1.

      A bientôt tout le monde,

      Damien.

    Reply to this message

Comment on this article

Who are you?
  • [Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom