WikiDOM

(ressuscité depuis https://web.archive.org/web/20140403072839/http://dev.over-blog.com/wikidom)

Overblog Kiwi a une particularité au niveau du stockage des sections texte dans les articles. Contrairement à Overblog v2 et à la quasi totalité des CMS, nous ne stockons pas du HTML. Stocker du HTML, c'est moche. Surtout quand il est issus d'un éditeur WYSIWYG, qu'il est rouvert par un éditeur WYSIWYG et qu'il est manipulé par des gens qui n'ont pas à savoir qu'il y a du HTML derrière. Quand nous voyions la soupe de HTML constituant la majorité des articles rédigés sur Overblog v2, nous n'avions qu'une seule envie : cadrer tout ça !

La triste réalité

Le problème, c'était que la seule alternative possible au HTML, c'était les langages de type WIKI : markdown, BBCode, Textile… Vous voyez le genre. Dotclear propose cette syntaxe dans son éditeur de post. Par défaut, on rédige son post dans un simple textarea qu'on peut donc mettre en page grâce à des codes wiki. L'inconvénient, c'est que ce n'est pas WYSIWYG. On peut alors switcher sur un éditeur HTML après avoir converti le wiki en HTML mais le retour en arrière n'est plus possible. Une approche qui ne nous convenait absolument pas : nos utilisateurs _VEULENT_ du WYSIWYG.

Alors on a fait une première tentative lors du développement du projet Wikio Expert. C'était parfaitement approprié : un outil dédié à la rédaction hyper cadrée et carte blanche sur les technos à utiliser. Alors on est parti sur le langage wiki que supportait Jelix à l'époque mais dont j'ai oublié le nom. L'idée était de stocker uniquement du Wiki en base de données. La difficulté était de renvoyer un rendu HTML au client pour qu'il l'affiche dans un éditeur WYSIWYG (facile), et qu'il sache convertir ce HTML en wiki lors de la sauvegarde du post (HARD !!).

Alors ça a marchouillé… des fois. C'était pas au point.

La belle réalité

Puis on a abandonné Wikio Expert pour écrire Overblog Kiwi from scratch. Avec la même carte blanche sur les technos. Mais cette fois, avec un atout inconsidérable ! Mediawiki, l'éditeur de Wikipedia venait juste de présenter VisualEditor : un éditeur WYSIWYG à l'état expérimental. Et cet éditeur était juste génial ! C'est celui que vous utilisez en ce moment.

Mediawiki a historiquement des contraintes bien plus strictes que les nôtres : tout leur contenu est stocké en wiki. C'est le principe du produit. Donc quand ils ont décidé de développer un éditeur WYSIWYG, il leur a fallu trouver un moyen de garder cette syntaxe. Ils ont ainsi créé le langage WikiDOM. Il s'agit d'un JSON décrivant la structure du texte sous forme d'enfants typés ayant leur propre contenu textuel annoté. Par exemple, ceci :

<p>Hello <strong>world</strong>!</p>  

donnera en WikiDOM :

{ type: "document" children: [{ type: "paragraph", content: { text: "Hello world!" }, annotations:[{ type: "textStyle/strong", range:{ start: 6, end: 11 } }] }] }

Ce qui est vachement plus beau. C'est en tout cas plus clair et plus strict que du html. Parce que le Hello World! là, tout con, quand on le passe dans un éditeur WYSIWYG, ça peut facilement devenir un truc du genre :

<p style="font-size:12pt"><span style="font-size:12pt">Hello <span style="font-weight: bold;">World</span>!</p>  

Visuellement, ça peut sembler la même chose, mais sémantiquement, ça ne veut plus rien dire.

Bref. Et donc, pour parvenir à ses fins, Mediawiki a écrit un éditeur WYSIWYG d'une façon que personne n'avait encore osé faire. Jusqu'ici, tous les éditeurs (TinyMCE, CKEditor, etc) utilisent une fonctionnalité du navigateur qui consiste à rendre éditable une iframe. La fonctionnalité d'édition WYSIWYG est une partie intégrante du browser. Le TinyMCE et le CKEditor ne servent qu'à créer l'interface autour de cette iframe pour y placer des boutons qui vont altérer le contenu de celle-ci et aider à le mettre en page. Et donc, c'est du HTML qui est généré différemment selon les navigateurs et qui peut imbriquer des balises inutiles sans que cela ne se voit à l'écran. En HTML5, cette fonctionnalité s'appelle contenteditable. C'est un attribut qui permet de rendre n'importe quel élément d'une page éditable.

VisualEditor de Mediawiki n'a pas fait usage de contendeditable. Il s'agit d'un textarea masqué qui intercepte les frappes clavier, met à jour son WikiDOM interne et affiche le rendu graphiquement. Résultat : nulle trace de HTML dans la manipulation des données. Du WikiDOM en entrée, des frappes clavier qui l'altèrent et du WikiDOM en sortie. Je suis tombé amoureux de cet éditeur au point de l'intégrer à Overblog Kiwi alors qu'il n'était encore qu'à l'état expérimental.

La dure réalité

Malgré ses immenses avantages, l'éditeur, encore à l'état expérimental avait (et a encore du coup) quelques inconvénients pénibles. Mais nous comptions sur les commit sur le svn de Mediawiki pour les voir disparaitre. Parmi ces inconvénients, un bug bloquant les caractères mort (deadkey) sur Mac : les ê par exemple ou alors l'impossibilité de coller du texte formaté. Tout cela étant du au passage par le textarea qui ne garde pas la mise en forme quand on lui colles du contenu dedans, contrairement au contenteditable.

Et c'est surement pour ça que le développement de VisualEditor a changé totalement de voie chez Mediawiki et est reparti, comme les autres, sur une base de contenteditable. Quel ne fut mon désarrois :( Bon, en plus ils ont abandonné le WikiDOM qu'on utilise depuis un an. Le nouveau VisualEditor prend du HTML en entrée et sort du HTML. Aucune différence avec les autres éditeurs, si ce n'est qu'il est très spécifiquement tweaké pour fonctionner avec Wikipedia. Du coup, il ne nous reste vraiment aucune raison de le mettre à jour.

Mais alors que faire ? Ne plus jamais évoluer ? Ou trouver une solution ?

L'une des réalité

Vous vous doutez qu'on a trouvé une solution sinon, la lecture de ce trop long article aurait été frustrante. Et bien oui, nous en avons trouvé et choisi une. Qui en plus nous permet de rajouter des fonctions manquantes à VisualEditor et que nous réclamaient les utilisateurs.

L'idée était de repartir sur un classique CKEditor que nous utilisions jadis sur Overblog v1 et v2.0. Overblog v2.1+ utilise un TinyMCE mais c'est kif kif. Pourquoi CKEditor ? Parce qu'il a énormément progressé et aujourd'hui semble être, dans sa version 4.0, l'intégration à la fois la plus propre et la plus fonctionnelle de contenteditable.

Bon. C'est bien beau tout ça, mais il reste le WikiDOM. Jusqu'ici, on ne s'était pas vraiment demandé comment ça fonctionnait, VisualEditor le gérait tout seul et le nombre de classes assez monstrueux m'avait découragé d'essayer de chercher à comprendre. Mais il fallait quand même trouver un moyen de convertir le WikiDOM stocké sur nos serveurs en HTML afin de l'envoyer dans le CKEditor mais surtout, transformer le HTML de sortie en WikiDOM afin de sauvegarder le post. On avait bien une solution bancale en PHP, mais elle était bancale.

Alors j'ai codé un module.

Du code !

Alors voilà enfin la section que vous attendiez tous, la présentation du code source. Alors ce code sera très certainement proposé dans son propre dépot github public très prochainement. En effet, il sera très utile pour les développeurs de clients tiers faisant joujou avec notre API publique. Cependant, il faudra que je le réécrive en enlevant toute référence à YUI ou à n'importe quelle autre dépendance.

![]/content/images/2015/08/ob5c0887capture-d-e-cran-2013-02-08-a-08-55-43.png/)

On a donc une série de classes de description d'un object WikiDOM :

Sachant que Document est l'objet racine dont on ne peut changer que la liste des enfants, que chaque élément HTML de type block (p, h1, h2, h3, pre, ol, li) devient un Child, que chaque Child contient un objet Content et que l'objet Content contient du texte et une liste d'Annotation qui sont les éléments de type inline (string, em, del, a).

Et donc cet objet Document propose une méthode asJson() qui permet de convertir tout ça en un simple et beau JSON sauvegardable en base de données.

Et puis on a une autre classe Converter qui permet de… wait for it… convertir ! dans les deux sens.

Deux méthodes statiques s'occupent de proposer au développeur une conversion de HTML vers WikiDOM et de WikiDOM vers HTML.

Pour développer tout ce code sensible, une batterie intense de tests unitaires. Qui m'auront été d'une utilité absolue car le code que je vous présente est en fait une deuxième version totalement réécrite. J'avais d'abord abordé le sujet en découpant le html en tant que chaine de caractère à coup de moultes expressions régulières. Puis une fois que tout fonctionnait, j'ai réalisé qu'on pouvait extrêmement simplifier l'algo en jouant simplement avec le DOM. Et c'est là que mes 43 tests unitaires m'ont permis d'être sur que mon nouveau code réalisait la même chose que le précédent. Mais avec 4 fois moins de lignes de code, et avec de meilleurs performances.

Best of all

Nous sommes donc maintenant totalement maitres de l'utilisation de ce WikiDOM et nous pouvons en faire ce qu'on veut. Et ce qu'on veut, c'est l'utiliser avec un excellent éditeur WYSIWYG pour satisfaire l'utilisateur et l'aider dans la rédaction d'articles de qualité et en l'empêchant de coller des spans et des styles dans tous les sens. On a donc le meilleur des deux mondes. Un cadrage strict, mais évolutif, et sans sacrifier l'expérience utilisateur : interface fluide, collage de texte formaté, correction automatique.

Hadrien

Hi, I'm a french Web Lead Developer, Front End Architect from Toulouse, France. I've worked for 7 years for Overblog then 2 years with AngularJS. Now, I'm a great fan of Aurelia.io.

Toulouse, France https://hadrien.eu