Supprime la couche de formes libres, déplace la navigation de page dans le panneau gauche
Build and deploy / test-python (push) Successful in 7m43s
Build and deploy / test-js (push) Successful in 57s
Build and deploy / lint-python (push) Successful in 5m29s
Build and deploy / lint-js (push) Failing after 1m16s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 5m42s

Formes libres (rectangle/cercle/triangle/trait) retirées de bout en
bout (bibliothèque, rendu, panneau Propriétés, grille d'accroche,
JS/CSS associés) — fonctionnalité non retenue.

La bande de vignettes visuelles des pages au-dessus du canevas est
remplacée par une section "Pages" dans le panneau de gauche (liste
simple : ajouter/renommer/réordonner (haut/bas)/supprimer), à la
place de l'ex-catégorie "Mise en page" de la bibliothèque. La route
document_edit ne rend plus qu'une seule page (celle affichée) au
chargement, au lieu de toutes les pages pour alimenter les anciennes
vignettes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-21 14:40:33 +02:00
co-authored by Claude Sonnet 5
parent 57c4de3d8a
commit 8dc4b35dcf
11 changed files with 220 additions and 597 deletions
+54 -59
View File
@@ -95,75 +95,70 @@
<div class="docBodyWrap">
<div class="docSidebarClose" id="docCloseLeft">← Retour au document</div>
<div class="docSidebar docSidebarLeft" id="docSidebarLeft">
<div class="docPageSection">
<div class="docSectionLabel">Pages</div>
<div class="docPageList" id="docPageList">
{% for page in pages %}
<div class="docPageListItem {{ 'is-active' if page.id == active_page.id else '' }}"
role="button"
tabindex="0"
data-page-id="{{ page.id }}">
{# //NOSONAR Web:S6819,Web:MouseEventWithoutKeyboardEquivalentCheck - div+role=button
volontaire : la rangée contient de vrais <button> d'action (monter/descendre/
renommer/supprimer), qu'un <button> englobant ne pourrait pas contenir
validement. L'équivalent clavier (Entrée/Espace) est posé côté JS
(forgeDocRenderPageList), donc le finding clavier de Sonar est un faux positif
: l'analyseur statique ne voit pas les addEventListener dynamiques. #}
<span class="docPageListTitle">{{ page.title }}</span>
<div class="docPageListActions">
<button type="button"
class="docPageListMove"
data-dir="up"
data-page-id="{{ page.id }}"
aria-label="Déplacer vers le haut"
title="Déplacer vers le haut">↑</button>
<button type="button"
class="docPageListMove"
data-dir="down"
data-page-id="{{ page.id }}"
aria-label="Déplacer vers le bas"
title="Déplacer vers le bas">↓</button>
<button type="button"
class="docPageListRename"
data-page-id="{{ page.id }}"
aria-label="Renommer cette page"
title="Renommer cette page">✎</button>
<button type="button"
class="docPageListDelete"
data-page-id="{{ page.id }}"
aria-label="Supprimer cette page"
title="Supprimer cette page">✕</button>
</div>
</div>
{% endfor %}
</div>
<button type="button" class="docBtnSecondary docPageListAdd" id="docPageListAdd">+ Ajouter une page</button>
</div>
{% for category_key, category in element_library.items() %}
<div>
<div class="docSectionLabel">{{ category.label }}</div>
{% if category_key == "mise_en_page" %}
<div class="docShapesGrid">
{% for kind in category.kinds %}
<div class="docLibItem docLibItem--shape"
draggable="true"
data-add="{{ kind }}">
<span class="docLibIcon docLibIcon--{{ kind }}"></span>
<span>{{ element_kind_labels[kind] }}</span>
</div>
{% endfor %}
</div>
{% else %}
<div class="docLibList">
{% for kind in category.kinds %}
<div class="docLibItem docLibItem--row"
draggable="true"
data-add="{{ kind }}">
<span class="docLibIcon docLibIcon--{{ kind }}"></span>
<span>{{ element_kind_labels[kind] }}</span>
</div>
{% endfor %}
</div>
{% endif %}
<div class="docLibList">
{% for kind in category.kinds %}
<div class="docLibItem docLibItem--row"
draggable="true"
data-add="{{ kind }}">
<span class="docLibIcon docLibIcon--{{ kind }}"></span>
<span>{{ element_kind_labels[kind] }}</span>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="docCanvasArea" id="docCanvasArea">
<div class="docPageThumbs" id="docPageTabs">
{% for page in pages %}
<div class="docPageThumbCard {{ 'is-active' if page.id == active_page.id else '' }}"
role="button"
tabindex="0"
data-page-id="{{ page.id }}"
draggable="true">
{# //NOSONAR Web:S6819,Web:MouseEventWithoutKeyboardEquivalentCheck - div+role=button
est ICI le bon choix, pas une entorse à l'accessibilité : la vignette englobe le
HTML réel de la page (rendered_pages[page.id]), qui peut contenir de vrais <button>
(Suivant/Recommencer d'un mini-jeu) ; un <button> dans un <button> est invalide et
le parseur HTML referme le bouton englobant trop tôt, corrompant l'arbre DOM (bug
constaté en jsdom ET reproductible dans un vrai navigateur, même algorithme de
parsing — voir CODE_QUALITY.md). L'équivalent clavier (Entrée/Espace) est posé côté
JS sur ces cartes (forgeDocRenderPageTabs), donc le finding clavier est un faux
positif : Sonar ne voit pas les addEventListener attachés dynamiquement. #}
<span class="docPageThumbFrame">
<span class="docPageThumbInner" data-page-id="{{ page.id }}" inert>{{ rendered_pages[page.id]|safe }}</span>
{# //NOSONAR S5247 - rendered_pages[page.id] vient de document_engine.render_document, même garantie que rendered_document plus bas (échappement déjà fait côté Python) #}
{# inert : les vrais <button>/liens éventuels du contenu de mini-jeu copié ici ne doivent jamais être atteignables au clavier (pure prévisualisation figée, pointer-events:none déjà côté CSS pour la souris) #}
<span class="docPageThumbDelete"
data-page-id="{{ page.id }}"
title="Supprimer cette page">✕</span>
</span>
<span class="docPageThumbLabel">{{ page.title }}</span>
</div>
{% endfor %}
<button type="button"
class="docPageThumbCard docPageThumbAddCard"
id="docPageTabAdd"
aria-label="Ajouter une page"
title="Ajouter une page">
<span class="docPageThumbFrame docPageThumbAddFrame">+</span>
</button>
</div>
<div class="docPage" id="docPage">
<div class="docPageContent" id="docPageContent">{{ rendered_document|safe }}</div>
{# //NOSONAR S5247 - rendered_document vient de document_engine.render_document, qui échappe (html.escape) tout contenu utilisateur avant interpolation (voir document_engine/rendering/render_document_element.py) ; jamais de HTML brut non échappé ici #}
<div class="docSnapGridOverlay" aria-hidden="true"></div>
</div>
<div class="docZoomPill">
<button type="button" id="docZoomOut" aria-label="Zoom -">−</button>