Build and deploy / test-python (push) Successful in 9m16s
Build and deploy / test-js (push) Successful in 51s
Build and deploy / lint-python (push) Successful in 4m11s
Build and deploy / lint-js (push) Failing after 1m23s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 4m14s
Remplace le bandeau scrollable multi-cartes par un vrai carrousel une-page-à-la-fois : un seul carré affiché (la page active), les grandes flèches ‹/› aux extrémités changent directement la page affichée (au lieu de juste faire défiler la vue). Les petites flèches ←/→ au-dessus du carré restent pour réordonner la page active parmi ses sœurs, sans changer l'affichage — distinctes des flèches de navigation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
228 lines
10 KiB
HTML
228 lines
10 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Forge Engine — {{ support.name }}{% endblock %}
|
||
{% block body_class %}objectEditBody{% endblock %}
|
||
{% block content_class %}{% endblock %}
|
||
{% block extra_head %}
|
||
<link rel="stylesheet"
|
||
href="{{ url_for('static', filename='document/document-editor.css') }}">
|
||
{% endblock %}
|
||
{% block content %}
|
||
<div class="docEditor3" id="docEditor3" data-slug="{{ support.slug }}">
|
||
<div class="docTopbar">
|
||
<div class="docCrumb">
|
||
<a href="{{ url_for('index') }}" class="docCrumbDim">Mes formations</a>
|
||
<svg width="14"
|
||
height="14"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M9 6l6 6-6 6" />
|
||
</svg>
|
||
<span class="docCrumbCur">{{ support.name }}</span>
|
||
</div>
|
||
<div class="docTopbarActions">
|
||
<button type="button"
|
||
class="docIconBtn"
|
||
id="docUndoBtn"
|
||
aria-label="Annuler"
|
||
disabled
|
||
title="Annuler (Ctrl+Z)">
|
||
<svg width="16"
|
||
height="16"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.8"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M8 6L4 10l4 4" />
|
||
<path d="M4 10h9a6 6 0 1 1-4.2 10.2" />
|
||
</svg>
|
||
</button>
|
||
<button type="button"
|
||
class="docIconBtn"
|
||
id="docRedoBtn"
|
||
aria-label="Rétablir"
|
||
disabled
|
||
title="Rétablir (Ctrl+Y)">
|
||
<svg width="16"
|
||
height="16"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.8"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M16 6l4 4-4 4" />
|
||
<path d="M20 10h-9a6 6 0 1 0 4.2 10.2" />
|
||
</svg>
|
||
</button>
|
||
<div class="docDividerV"></div>
|
||
<button type="button"
|
||
class="docBtnSecondary docBtnPrimary"
|
||
id="docPreviewBtn">
|
||
<svg width="16"
|
||
height="16"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="1.8"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6-10-6-10-6z" />
|
||
<circle cx="12" cy="12" r="3" />
|
||
</svg><span class="docBtnLabel">Aperçu</span>
|
||
</button>
|
||
<div class="docDividerV"></div>
|
||
<div class="docWidthPicker"
|
||
id="docWidthPicker"
|
||
role="group"
|
||
aria-label="Largeur d'aperçu">
|
||
<button type="button" class="docWidthBtn is-active" data-width="">Bureau</button>
|
||
<button type="button" class="docWidthBtn" data-width="768">Tablette</button>
|
||
<button type="button" class="docWidthBtn" data-width="375">Mobile</button>
|
||
</div>
|
||
<div class="docDividerV"></div>
|
||
<button type="button"
|
||
class="docIconBtn docThemeToggle"
|
||
id="docThemeToggle"
|
||
aria-label="Changer de thème"></button>
|
||
</div>
|
||
</div>
|
||
<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="docPageStrip">
|
||
<button type="button"
|
||
class="docPageStripNav"
|
||
id="docPageStripPrev"
|
||
aria-label="Page précédente"
|
||
title="Page précédente">‹</button>
|
||
<div class="docPageList" id="docPageList">
|
||
{# active_page est toujours pages[0] au chargement initial (voir
|
||
routes/document/document_edit.py) — index 0 fixe, jamais recalculé
|
||
ici ; un changement de page ensuite est entièrement géré côté
|
||
client par forgeDocRenderPageList, qui recalcule le VRAI index. #}
|
||
{% set active_index = 0 %}
|
||
<div class="docPageListItem is-active" role="button" tabindex="0" data-page-id="{{ active_page.id }}">
|
||
{# //NOSONAR Web:S6819,Web:MouseEventWithoutKeyboardEquivalentCheck - div+role=button
|
||
volontaire : la rangée contient de vrais <button> d'action (réordonner/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. #}
|
||
<div class="docPageListActions">
|
||
<button type="button"
|
||
class="docPageListMove"
|
||
data-dir="up"
|
||
data-page-id="{{ active_page.id }}"
|
||
aria-label="Réordonner vers la gauche"
|
||
title="Réordonner vers la gauche"
|
||
{{ 'disabled' if active_index == 0 else '' }}>←</button>
|
||
<button type="button"
|
||
class="docPageListMove"
|
||
data-dir="down"
|
||
data-page-id="{{ active_page.id }}"
|
||
aria-label="Réordonner vers la droite"
|
||
title="Réordonner vers la droite"
|
||
{{ 'disabled' if active_index == pages|length - 1 else '' }}>→</button>
|
||
<button type="button"
|
||
class="docPageListRename"
|
||
data-page-id="{{ active_page.id }}"
|
||
aria-label="Renommer cette page"
|
||
title="Renommer cette page">✎</button>
|
||
<button type="button"
|
||
class="docPageListDelete"
|
||
data-page-id="{{ active_page.id }}"
|
||
aria-label="Supprimer cette page"
|
||
title="Supprimer cette page"
|
||
{{ 'disabled' if pages|length <= 1 else '' }}>✕</button>
|
||
</div>
|
||
<div class="docPageListSquare">{{ active_index + 1 }}</div>
|
||
<span class="docPageListTitle"><span class="docPageListTitleText">{{ active_page.title }}</span></span>
|
||
<span class="docPageListCounter">{{ active_index + 1 }} / {{ pages|length }}</span>
|
||
</div>
|
||
</div>
|
||
<button type="button"
|
||
class="docPageStripNav"
|
||
id="docPageStripNext"
|
||
aria-label="Page suivante"
|
||
title="Page suivante">›</button>
|
||
</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>
|
||
<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="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>
|
||
<div class="docZoomPill">
|
||
<button type="button" id="docZoomOut" aria-label="Zoom -">−</button>
|
||
<span id="docZoomVal">100%</span>
|
||
<button type="button" id="docZoomIn" aria-label="Zoom +">+</button>
|
||
</div>
|
||
<div class="docPageNavPill" id="docPageNavPill">
|
||
<button type="button" id="docPagePrevBtn" aria-label="Page précédente">‹</button>
|
||
<span id="docPageNavLabel"></span>
|
||
<button type="button" id="docPageNextBtn" aria-label="Page suivante">›</button>
|
||
</div>
|
||
</div>
|
||
<div class="docSidebarClose" id="docCloseRight">← Retour au document</div>
|
||
<div class="docSidebar docSidebarRight" id="docSidebarRight">
|
||
<div id="docPropsPanel">
|
||
<div class="docSectionLabel">Propriétés</div>
|
||
<div class="docEmptyState">Sélectionnez un élément du document pour voir ses propriétés.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="docBottomNav" id="docBottomNav">
|
||
<button type="button" data-target="left">Éléments</button>
|
||
<button type="button" data-target="doc" class="is-active">Document</button>
|
||
<button type="button" data-target="right">Propriétés</button>
|
||
</div>
|
||
</div>
|
||
<div class="docModalBackdrop" id="docScenarioTreeModal">
|
||
<div class="docModalDialog">
|
||
<div class="docModalHeader">
|
||
<span class="docModalTitle" id="docScenarioTreeModalTitle">Arbre du scénario</span>
|
||
<button type="button"
|
||
class="docModalCloseBtn"
|
||
id="docScenarioTreeModalClose"
|
||
aria-label="Fermer">✕</button>
|
||
</div>
|
||
<div class="docModalBody" id="docScenarioTreeModalBody"></div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
window.FORGE_DOCUMENT = {
|
||
slug: {{ support.slug|tojson }},
|
||
elements: {{ elements|tojson }},
|
||
elementKindLabels: {{ element_kind_labels|tojson }},
|
||
pages: {{ pages|tojson }},
|
||
activePageId: {{ active_page.id|tojson }}
|
||
};
|
||
</script>
|
||
<script src="{{ url_for('static', filename='document/js/document-editor.js') }}"></script>
|
||
{% endblock %}
|