Les blocs

Unité de base de Rédac — Block, Paragraph, Block_manager

Block — classe de base

Tous les blocs héritent de Block. Elle génère un id aléatoire et crée le _wrapper (div vide). Les sous-classes ajoutent leur structure dans render().

Propriété / méthodeDescription
get id()Identifiant unique généré par Utils.rdm_id() — aussi l'attribut id du DOM
get type()Type du bloc : 'paragraph', 'heading', etc.
render()Block retourne _wrapper (div vide). À surcharger pour ajouter la structure DOM de chaque type de bloc.
save()À implémenter dans la sous-classe — non défini dans Block. Doit retourner { type, data } pour la sérialisation.
static load(saved)À implémenter dans la sous-classe — non défini dans Block. Reconstruit un bloc depuis un objet JSON sauvegardé.
Block ne pose aucune classe CSS. C'est à chaque sous-classe de gérer son propre style. Cela permet à chaque type de bloc d'avoir sa propre structure DOM.

Paragraph — bloc concret

Seul type de bloc implémenté pour l'instant. Structure DOM produite par render() :

<div class="rdac-block" id="{id}">      ← position:relative, display:flex
    <div class="rdac-tools">            ← flex item gauche (52px)
        <button class="rdac-tool-btn">+</button>
        <button class="rdac-tool-btn">⋮</button>
    </div>
    <div class="rdac-content"
         contenteditable="true"></div> ← flex item droit (flex:1)
    <div class="rdac-tune-dd"
         style="display:none">          ← position:absolute, dropdown
        ...
    </div>
</div>
Pourquoi display:flex sur .rdac-block ?

L'approche intuitive serait de placer les boutons + et en position:absolute; left:-52px — hors du bloc, dans la marge gauche. Le problème : si un parent a overflow:hidden (c'est le cas de .start-window-body dans le dashboard Alluvia), les boutons sont clippés et invisibles.

Avec display:flex, les boutons sont le premier flex item (52px de large). Ils restent dans le flux et ne sortent jamais du container. Le dropdown Tune utilise position:absolute — il sort du flux flex mais reste positionné par rapport à .rdac-block (position:relative).

Méthodes de Paragraph
MéthodeDescription
get tune()Accès au composant Tune du bloc (pour que Redac câble les callbacks)
get content_el()Accès au div.rdac-content (pour _split_block)
focus()Focus + curseur placé à la fin via l'API Range
save()Retourne { type: 'paragraph', data: { text: innerHTML } }
static load(saved)Crée un Paragraph et injecte saved.data.text dans le contenu

Block_manager — tableau ordonné

Maintient la liste des blocs dans l'ordre du document. C'est la source de vérité pour l'ordre — le DOM est toujours synchronisé avec ce tableau par Redac.

MéthodeDescription
add(block)Ajoute en fin de liste
insert_after(ref_id, block)Insère après l'id de référence (ou en fin si non trouvé)
rm(id)Retire de la liste
up(id) / down(id)Swap avec le voisin (synchronisé manuellement avec le DOM)
get(id) / get_index(id)Accès par id
get_previous(id) / get_next(id)Navigation dans la liste
is_first(id) / is_last(id)Disponibles pour usage externe. _refresh_states() compare directement les indices du forEach (i === 0) sans appeler ces méthodes.
size()Nombre de blocs (si size() === 1 → bouton Supprimer désactivé)
DOM et Block_manager sont toujours synchronisés manuellement par Redac. Quand Redac déplace un bloc dans le DOM (insertBefore), il appelle aussitôt blocks.up(id) ou blocks.down(id), puis _refresh_states() pour mettre à jour les boutons.

Ajouter un type de bloc

Le vrai test qu'une architecture est extensible : peut-on ajouter un type en changeant le moins de fichiers possible ? Pour Rédac, la réponse est 3 étapes :

  1. Créer mon_bloc.js qui hérite de Block. Implémenter render(), save(), static load(saved), et exposer get tune() si le bloc est éditable.
  2. Dans redac.js, ajouter la classe dans la type_map de load() : { paragraph: Paragraph, heading: Heading }
  3. Si le bloc peut être ajouté par l'utilisateur (via le bouton +), adapter _add_block() pour choisir le bon type.