2 Commits
Author SHA1 Message Date
Claude cc33cf5fbc Informations : éditeur visuel à la place de la syntaxe Markdown
La barre d'outils écrivait des étoiles dans un textarea : l'adhérent qui
rédigeait devait connaître une syntaxe pour obtenir du gras. On édite
désormais comme dans un traitement de texte — on sélectionne, on clique sur
G, le texte devient gras à l'écran.

Le format stocké ne change pas d'un octet. C'est tout l'enjeu : le WYSIWYG
porte sur la saisie, pas sur le stockage. À chaque frappe, le navigateur
retraverse ce qu'il a édité (serializeToRichText) et n'en garde que le gras,
l'italique, les listes, les sous-titres et les liens ; le balisage part dans
un champ caché et le serveur le ré-analyse avec l'analyseur existant. Le HTML
de l'éditeur ne quitte jamais la page, donc aucun assainisseur HTML n'entre
dans le produit — le risque n'a jamais été la surface d'édition, mais la base.

- rich-text-dom.ts : sérialiseur pur, testable sans navigateur (MinimalNode).
  Il lit aussi le gras codé en style CSS, pour qu'un brouillon collé depuis
  Google Docs ne perde pas sa mise en forme ; le style explicite l'emporte sur
  la balise, sinon le <b style="font-weight:normal"> dont Docs enveloppe tout
  document mettrait le texte entier en gras.
- Un collage passe par DOMParser, dont le document est inerte : un <img
  onerror> collé ne s'exécute pas. Seul du HTML produit par nous est réinjecté.
- L'italique s'écrit _ainsi_ : **_x_** est lisible par l'analyseur là où ***x***
  serait ambigu. Un tiret bas au milieu d'un mot n'ouvre rien.
- saveInformation normalise les CRLF que l'encodage des formulaires introduit.

Vérifié au navigateur contre une base réelle : aller-retour identique après
enregistrement, et un collage hostile (script, img onerror, iframe, style,
lien javascript:) ressort en texte structuré sans qu'une seule alerte parte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QsLjRAnuLwivqxCbM4WeP
2026-09-15 06:37:52 +00:00
Claude 1701fc2834 Analyseur de texte riche pour les informations adhérents
Sous-ensemble de Markdown — gras, italique, listes, liens, sous-titres —
analysé par `src/lib/rich-text.ts` puis rendu en éléments React, jamais en
HTML brut : même principe que le journal d'activité. Un éditeur WYSIWYG
aurait imposé de stocker du HTML tiers puis de l'assainir, soit une
seconde dépendance et une seconde surface d'attaque.

Deux rendus, un seul analyseur : `richTextNodes()` pour l'écran,
`richTextToEmailHtml()` pour le message. L'aperçu du formulaire passera
par le premier, il sera donc fidèle par construction.

`safeHttpUrl()` remplace le `webUrl()` privé d'`email-templates.ts` : un
lien hors http/https perd sa cible et ne garde que son libellé.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QsLjRAnuLwivqxCbM4WeP
2026-09-14 15:28:37 +00:00