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éthode | Description |
|---|---|
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éthode | Description |
|---|---|
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éthode | Description |
|---|---|
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é) |
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 :
-
Créer
mon_bloc.jsqui hérite deBlock. Implémenterrender(),save(),static load(saved), et exposerget tune()si le bloc est éditable. -
Dans
redac.js, ajouter la classe dans latype_mapdeload():{ paragraph: Paragraph, heading: Heading } -
Si le bloc peut être ajouté par l'utilisateur (via le bouton
+), adapter_add_block()pour choisir le bon type.