Flux d'une opération

Comment l'éditeur communique avec PHP

La règle fondamentale

Rédac distingue trois régimes de fonctionnement :

Typing — client only
Taper du texte dans le contenteditable. Aucun round-trip. Le texte est synchronisé avec PHP sur le blur du bloc.
Formatting — op PHP
Gras, lien, conversion de type… envoie une opération à PHP via fetch. PHP transforme le modèle et renvoie le HTML du bloc. HTMX swaps.
Sync — blur
Quand le focus quitte un bloc, le JS envoie le contenu DOM (nodes JSON) à PHP pour mettre à jour le modèle en session.

Cycle complet — exemple : Ctrl+B sur "world"

1. User : sélectionne "world", appuie Ctrl+B

2. JS   : sel_save(contenteditable)
          → { from: 6, to: 11 }   (offsets en caractères)

3. JS   : POST /redac/op  {
              op:       'toggle_mark',
              mark:     'bold',
              block_id: 'b1a2c3',
              from:     6,
              to:       11,
              nodes:    '[...]'   (snapshot du DOM actuel)
          }

4. PHP  : sync le texte depuis `nodes`
          → Mark_op::toggle($nodes, 'bold', 6, 11)
          → inner_html() → rendu HTML du bloc

5. PHP  : retourne le HTML de _block.php

6. JS   : swap outerHTML du bloc dans le DOM
          → attach_block(new_el)
          → sel_restore(contenteditable, { from: 6, to: 11 })

La restauration de la sélection (sel_restore) fonctionne par offset en caractères — pas par nœud DOM. Elle survit donc au swap HTMX qui recrée tous les nœuds.

Opérations (POST /op)

Toutes les opérations passent par un seul endpoint POST /redac/op. Chaque op empile l'état courant sur la stack undo avant de modifier.

opDescriptionRetourne
toggle_markToggle bold / italic / underlineHTML du bloc
set_link / remove_linkPoser / retirer un lienHTML du bloc
set_marker / remove_markerSurlignement couleurHTML du bloc
set_color / remove_colorCouleur texteHTML du bloc
reset_marksEffacer tous les marksHTML du bloc
set_from_htmlInjecter du HTML brut (source panel)HTML du bloc
add_blockInsérer un nouveau bloc après un idHTML du nouveau bloc
remove_blockSupprimer un blocJSON {ok:true}
split_blockCouper au curseur (Enter)HTML des deux blocs
merge_blockFusionner avec le précédent (Backspace)HTML du bloc précédent
convert_blockChanger le type du blocHTML du bloc
update_attrsModifier id_attr / classesHTML du bloc
update_sepOptions du séparateurHTML du bloc
update_imageOptions de l'imageHTML du bloc

Undo

Avant chaque opération, l'état complet du document est poussé sur une stack en session PHP (max 20 entrées). Ctrl+Z dépile le dernier état et re-rend l'intégralité de l'éditeur.