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
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:
co-authored by
Claude Sonnet 5
parent
57c4de3d8a
commit
8dc4b35dcf
@@ -19,14 +19,6 @@ var FORGE_DOC_STYLE_PRESETS = {
|
||||
legende: 'Légende',
|
||||
};
|
||||
|
||||
// Même raison que FORGE_DOC_STYLE_PRESETS ci-dessus.
|
||||
// eslint-disable-next-line no-var, vars-on-top
|
||||
var FORGE_DOC_SHAPE_KINDS = ['rectangle', 'cercle', 'triangle', 'trait'];
|
||||
|
||||
function forgeDocIsShapeKind(kind) {
|
||||
return FORGE_DOC_SHAPE_KINDS.includes(kind);
|
||||
}
|
||||
|
||||
function forgeDocChildrenOf(parentId) {
|
||||
return window.forgeDocState.elements
|
||||
.filter((el) => el.parent_id === parentId)
|
||||
@@ -116,15 +108,6 @@ function forgeDocRefreshCanvas() {
|
||||
window.forgeDocState.selectedId = null;
|
||||
forgeDocRenderProps(null);
|
||||
}
|
||||
// La vignette miniature de la page ACTIVE (voir .docPageThumbInner,
|
||||
// static/document/document-editor.css) reflète le MÊME rendu que le
|
||||
// canevas principal — seule cette page peut avoir changé tant qu'on
|
||||
// ne l'a pas quittée (voir forgeDocSwitchPage), jamais besoin de
|
||||
// reconstruire toute la bande de vignettes ici.
|
||||
const { activePageId } = window.forgeDocState;
|
||||
window.forgeDocState.pageThumbsHtml[activePageId] = data.html;
|
||||
const thumbInner = document.querySelector(`.docPageThumbInner[data-page-id="${activePageId}"]`);
|
||||
if (thumbInner) thumbInner.innerHTML = data.html;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -236,8 +219,7 @@ function forgeDocUpdateAttributes(id, newAttributes) {
|
||||
* ------------------------------------------------------------------- */
|
||||
|
||||
function forgeDocFindDropTarget(clientX, clientY) {
|
||||
const candidates = Array.from(document.querySelectorAll('#docPage [data-element-id]'))
|
||||
.filter((dom) => !forgeDocIsShapeKind(dom.dataset.kind));
|
||||
const candidates = Array.from(document.querySelectorAll('#docPage [data-element-id]'));
|
||||
let best = null;
|
||||
let bestDist = Infinity;
|
||||
candidates.forEach((dom) => {
|
||||
@@ -421,10 +403,13 @@ function forgeDocBindCanvasDropZone() {
|
||||
/* ---------------------------------------------------------------------
|
||||
* Pages — un support est composé de plusieurs pages (retour utilisateur
|
||||
* du 21/09/2026 : "il faut implémenter un système de page"), chacune un
|
||||
* document indépendant affiché SEUL sur le canevas à la fois. Bande
|
||||
* d'ONGLETS au-dessus du canevas pour créer/renommer (double-clic)/
|
||||
* réordonner (glisser)/supprimer (voir templates/document/
|
||||
* document_edit.html) — jamais un panneau latéral (retour utilisateur).
|
||||
* document indépendant affiché SEUL sur le canevas à la fois. Section
|
||||
* dédiée dans le panneau GAUCHE (retour utilisateur du 21/09/2026 :
|
||||
* "une section qui s'ajoute dans le panneau de gauche pour ajouter une
|
||||
* page et naviguer entre elles", à la place de l'ex-catégorie "Mise en
|
||||
* page"/formes libres, supprimée) — une simple liste, jamais de vignette
|
||||
* visuelle (voir templates/document/document_edit.html, .docPageList) :
|
||||
* créer/renommer (bouton crayon)/réordonner (boutons haut/bas)/supprimer.
|
||||
* Changer de page VIDE la pile Annuler/Rétablir (voir forgeDocSwitchPage)
|
||||
* : une commande empilée sur une autre page rejouerait un appel AJAX
|
||||
* ciblant des éléments qui ne sont plus affichés, aucun sens à la garder.
|
||||
@@ -484,7 +469,7 @@ function forgeDocSwitchPage(pageId) {
|
||||
forgeDocUpdateHistoryButtons();
|
||||
window.forgeDocState.selectedId = null;
|
||||
forgeDocRenderProps(null);
|
||||
forgeDocRenderPageTabs();
|
||||
forgeDocRenderPageList();
|
||||
forgeDocUpdatePageNavPill();
|
||||
return forgeDocRefreshCanvas();
|
||||
}
|
||||
@@ -494,11 +479,6 @@ function forgeDocAddPage() {
|
||||
window.forgeDocState.pages.push({
|
||||
id: result.id, title: result.title, order_index: window.forgeDocState.pages.length,
|
||||
});
|
||||
// Vignette vide (aucun élément sur une page neuve) — forgeDocRefreshCanvas
|
||||
// la remplacera de toute façon juste après via forgeDocSwitchPage, posé
|
||||
// ici explicitement plutôt que de compter sur le repli `|| ''` de
|
||||
// forgeDocRenderPageTabs.
|
||||
window.forgeDocState.pageThumbsHtml[result.id] = '';
|
||||
return forgeDocSwitchPage(result.id);
|
||||
});
|
||||
}
|
||||
@@ -507,7 +487,7 @@ function forgeDocRenamePage(pageId, title) {
|
||||
return forgeDocApiPageRename(pageId, title).then((result) => {
|
||||
const page = window.forgeDocState.pages.find((p) => p.id === pageId);
|
||||
if (page) page.title = result.title;
|
||||
forgeDocRenderPageTabs();
|
||||
forgeDocRenderPageList();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -522,15 +502,31 @@ function forgeDocDeletePage(pageId) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
window.forgeDocState.pages = window.forgeDocState.pages.filter((p) => p.id !== pageId);
|
||||
delete window.forgeDocState.pageThumbsHtml[pageId];
|
||||
if (window.forgeDocState.activePageId === pageId) {
|
||||
return forgeDocSwitchPage(forgeDocOrderedPages()[0].id);
|
||||
}
|
||||
forgeDocRenderPageTabs();
|
||||
forgeDocRenderPageList();
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function forgeDocMovePage(pageId, direction) {
|
||||
const ordered = forgeDocOrderedPages();
|
||||
const index = ordered.findIndex((p) => p.id === pageId);
|
||||
const newIndex = direction === 'up' ? index - 1 : index + 1;
|
||||
if (newIndex < 0 || newIndex >= ordered.length) return;
|
||||
forgeDocApiPageMove(pageId, newIndex).then(() => {
|
||||
const moved = window.forgeDocState.pages.find((p) => p.id === pageId);
|
||||
const rest = window.forgeDocState.pages
|
||||
.filter((p) => p.id !== pageId)
|
||||
.sort((a, b) => a.order_index - b.order_index);
|
||||
rest.splice(newIndex, 0, moved);
|
||||
rest.forEach((p, i) => { p.order_index = i; });
|
||||
window.forgeDocState.pages = rest;
|
||||
forgeDocRenderPageList();
|
||||
});
|
||||
}
|
||||
|
||||
function forgeDocSelectAllText(el) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
@@ -539,9 +535,10 @@ function forgeDocSelectAllText(el) {
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
function forgeDocStartRenamingPageTab(titleEl) {
|
||||
const tab = titleEl.closest('.docPageThumbCard');
|
||||
const pageId = Number(tab.dataset.pageId);
|
||||
function forgeDocStartRenamingPage(pageId) {
|
||||
const item = document.querySelector(`.docPageListItem[data-page-id="${pageId}"]`);
|
||||
if (!item) return;
|
||||
const titleEl = item.querySelector('.docPageListTitle');
|
||||
const original = titleEl.textContent;
|
||||
titleEl.setAttribute('contenteditable', 'true');
|
||||
titleEl.focus();
|
||||
@@ -578,107 +575,60 @@ function forgeDocStartRenamingPageTab(titleEl) {
|
||||
titleEl.addEventListener('keydown', onKeydown);
|
||||
}
|
||||
|
||||
function forgeDocRenderPageTabs() {
|
||||
const container = document.getElementById('docPageTabs');
|
||||
function forgeDocRenderPageList() {
|
||||
const container = document.getElementById('docPageList');
|
||||
if (!container) return;
|
||||
const pages = forgeDocOrderedPages();
|
||||
container.classList.toggle('docPageTabs--single', pages.length <= 1);
|
||||
// Le contenu de chaque vignette (.docPageThumbInner) vient du CACHE
|
||||
// client (window.forgeDocState.pageThumbsHtml, alimenté au chargement
|
||||
// et tenu à jour par forgeDocRefreshCanvas) — jamais ré-échappé ici :
|
||||
// c'est déjà du HTML de confiance produit par document_engine.
|
||||
// render_document côté serveur (même contrat que data.html pour le
|
||||
// canevas principal), pas du texte libre du créateur.
|
||||
// div + role="button" ici, jamais <button> : le contenu de la vignette
|
||||
// (pageThumbsHtml) est le HTML réel de la page, 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. L'équivalent clavier
|
||||
// (Entrée/Espace) est posé plus bas ; inert neutralise les vrais
|
||||
// boutons copiés dans la vignette (jamais atteignables au clavier).
|
||||
const cardsHtml = pages.map((p) => `
|
||||
<div class="docPageThumbCard ${p.id === window.forgeDocState.activePageId ? 'is-active' : ''}"
|
||||
// div + role="button" ici, jamais <button> : 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é plus bas.
|
||||
container.innerHTML = pages.map((p, index) => `
|
||||
<div class="docPageListItem ${p.id === window.forgeDocState.activePageId ? 'is-active' : ''}"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-page-id="${p.id}"
|
||||
draggable="true">
|
||||
<span class="docPageThumbFrame">
|
||||
<span class="docPageThumbInner" data-page-id="${p.id}" inert>${window.forgeDocState.pageThumbsHtml[p.id] || ''}</span>
|
||||
<span class="docPageThumbDelete" data-page-id="${p.id}" title="Supprimer cette page">✕</span>
|
||||
</span>
|
||||
<span class="docPageThumbLabel">${forgeDocEscapeHtml(p.title)}</span>
|
||||
data-page-id="${p.id}">
|
||||
<span class="docPageListTitle">${forgeDocEscapeHtml(p.title)}</span>
|
||||
<div class="docPageListActions">
|
||||
<button type="button" class="docPageListMove" data-dir="up" data-page-id="${p.id}" aria-label="Déplacer vers le haut" title="Déplacer vers le haut"${index === 0 ? ' disabled' : ''}>↑</button>
|
||||
<button type="button" class="docPageListMove" data-dir="down" data-page-id="${p.id}" aria-label="Déplacer vers le bas" title="Déplacer vers le bas"${index === pages.length - 1 ? ' disabled' : ''}>↓</button>
|
||||
<button type="button" class="docPageListRename" data-page-id="${p.id}" aria-label="Renommer cette page" title="Renommer cette page">✎</button>
|
||||
<button type="button" class="docPageListDelete" data-page-id="${p.id}" aria-label="Supprimer cette page" title="Supprimer cette page"${pages.length <= 1 ? ' disabled' : ''}>✕</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
container.innerHTML = `${cardsHtml}<button type="button" class="docPageThumbCard docPageThumbAddCard" id="docPageTabAdd" aria-label="Ajouter une page" title="Ajouter une page"><span class="docPageThumbFrame docPageThumbAddFrame">+</span></button>`;
|
||||
|
||||
container.querySelectorAll('.docPageThumbCard[data-page-id]').forEach((card) => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('docPageThumbDelete')) return;
|
||||
forgeDocSwitchPage(Number(card.dataset.pageId));
|
||||
container.querySelectorAll('.docPageListItem[data-page-id]').forEach((item) => {
|
||||
item.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.docPageListActions')) return;
|
||||
forgeDocSwitchPage(Number(item.dataset.pageId));
|
||||
});
|
||||
card.addEventListener('keydown', (e) => {
|
||||
item.addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'Enter' && e.key !== ' ') return;
|
||||
e.preventDefault();
|
||||
forgeDocSwitchPage(Number(card.dataset.pageId));
|
||||
forgeDocSwitchPage(Number(item.dataset.pageId));
|
||||
});
|
||||
});
|
||||
container.querySelectorAll('.docPageThumbLabel').forEach((labelEl) => {
|
||||
labelEl.addEventListener('dblclick', (e) => {
|
||||
container.querySelectorAll('.docPageListMove').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
forgeDocStartRenamingPageTab(labelEl);
|
||||
forgeDocMovePage(Number(btn.dataset.pageId), btn.dataset.dir);
|
||||
});
|
||||
});
|
||||
container.querySelectorAll('.docPageThumbDelete').forEach((btn) => {
|
||||
container.querySelectorAll('.docPageListRename').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
forgeDocStartRenamingPage(Number(btn.dataset.pageId));
|
||||
});
|
||||
});
|
||||
container.querySelectorAll('.docPageListDelete').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
forgeDocDeletePage(Number(btn.dataset.pageId));
|
||||
});
|
||||
});
|
||||
document.getElementById('docPageTabAdd').addEventListener('click', () => forgeDocAddPage());
|
||||
}
|
||||
|
||||
function forgeDocBindPageTabsDrag() {
|
||||
// Délégation sur le CONTENEUR (jamais les vignettes elles-mêmes,
|
||||
// recréées à chaque forgeDocRenderPageTabs) : un seul jeu de listeners
|
||||
// pour toute la session, même principe que forgeDocMotsBindGlobalMouseup.
|
||||
const container = document.getElementById('docPageTabs');
|
||||
let draggedId = null;
|
||||
|
||||
container.addEventListener('dragstart', (e) => {
|
||||
const card = e.target.closest('.docPageThumbCard');
|
||||
if (!card || !card.dataset.pageId) return;
|
||||
draggedId = Number(card.dataset.pageId);
|
||||
card.classList.add('is-dragging');
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
});
|
||||
container.addEventListener('dragend', (e) => {
|
||||
const card = e.target.closest('.docPageThumbCard');
|
||||
if (card) card.classList.remove('is-dragging');
|
||||
});
|
||||
container.addEventListener('dragover', (e) => {
|
||||
if (draggedId !== null) e.preventDefault();
|
||||
});
|
||||
container.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
if (draggedId === null) return;
|
||||
const targetCard = e.target.closest('.docPageThumbCard[data-page-id]');
|
||||
const ordered = forgeDocOrderedPages();
|
||||
const newIndex = targetCard
|
||||
? ordered.findIndex((p) => p.id === Number(targetCard.dataset.pageId))
|
||||
: ordered.length - 1;
|
||||
const movedId = draggedId;
|
||||
draggedId = null;
|
||||
forgeDocApiPageMove(movedId, newIndex).then(() => {
|
||||
const moved = window.forgeDocState.pages.find((p) => p.id === movedId);
|
||||
const rest = window.forgeDocState.pages
|
||||
.filter((p) => p.id !== movedId)
|
||||
.sort((a, b) => a.order_index - b.order_index);
|
||||
rest.splice(newIndex, 0, moved);
|
||||
rest.forEach((p, i) => { p.order_index = i; });
|
||||
window.forgeDocState.pages = rest;
|
||||
forgeDocRenderPageTabs();
|
||||
});
|
||||
});
|
||||
const addBtn = document.getElementById('docPageListAdd');
|
||||
if (addBtn) addBtn.onclick = () => forgeDocAddPage();
|
||||
}
|
||||
|
||||
function forgeDocBindPageNavPill() {
|
||||
@@ -694,59 +644,6 @@ function forgeDocBindPageNavPill() {
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Formes libres — position absolue, glissées à la souris (pas de HTML5
|
||||
* DnD, pas de logique de rangée) avec grille d'accroche réelle.
|
||||
* ------------------------------------------------------------------- */
|
||||
|
||||
// Même raison que FORGE_DOC_STYLE_PRESETS en tête de fichier.
|
||||
// eslint-disable-next-line no-var, vars-on-top
|
||||
var FORGE_DOC_SNAP_SIZE = 8;
|
||||
|
||||
function forgeDocBindShapeDrag(dom, elementId) {
|
||||
dom.addEventListener('mousedown', (e) => {
|
||||
if (window.forgeDocState.previewMode) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
forgeDocSelectElement(elementId);
|
||||
const el = window.forgeDocState.elementsById[elementId];
|
||||
window.forgeDocState.shapeDrag = {
|
||||
id: elementId,
|
||||
startX: e.clientX,
|
||||
startY: e.clientY,
|
||||
origX: el.attributes.x,
|
||||
origY: el.attributes.y,
|
||||
};
|
||||
document.getElementById('docPage').classList.add('docPage--dragging-shape');
|
||||
});
|
||||
}
|
||||
|
||||
function forgeDocBindShapeDragGlobalHandlers() {
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
const drag = window.forgeDocState.shapeDrag;
|
||||
if (!drag) return;
|
||||
const zoomFactor = window.forgeDocState.zoom / 100;
|
||||
const dx = (e.clientX - drag.startX) / zoomFactor;
|
||||
const dy = (e.clientY - drag.startY) / zoomFactor;
|
||||
const newX = Math.round((drag.origX + dx) / FORGE_DOC_SNAP_SIZE) * FORGE_DOC_SNAP_SIZE;
|
||||
const newY = Math.round((drag.origY + dy) / FORGE_DOC_SNAP_SIZE) * FORGE_DOC_SNAP_SIZE;
|
||||
const dom = document.querySelector(`[data-element-id="${drag.id}"]`);
|
||||
if (dom) { dom.style.left = `${newX}px`; dom.style.top = `${newY}px`; }
|
||||
drag.lastX = newX;
|
||||
drag.lastY = newY;
|
||||
});
|
||||
document.addEventListener('mouseup', () => {
|
||||
const drag = window.forgeDocState.shapeDrag;
|
||||
if (!drag) return;
|
||||
window.forgeDocState.shapeDrag = null;
|
||||
document.getElementById('docPage').classList.remove('docPage--dragging-shape');
|
||||
if (typeof drag.lastX === 'number' && (drag.lastX !== drag.origX || drag.lastY !== drag.origY)) {
|
||||
const el = window.forgeDocState.elementsById[drag.id];
|
||||
forgeDocUpdateAttributes(drag.id, { ...el.attributes, x: drag.lastX, y: drag.lastY });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Sélection & panneau Propriétés.
|
||||
* ------------------------------------------------------------------- */
|
||||
@@ -758,15 +655,11 @@ function forgeDocBindCanvasInteractions() {
|
||||
e.stopPropagation();
|
||||
forgeDocSelectElement(elementId);
|
||||
});
|
||||
if (forgeDocIsShapeKind(dom.dataset.kind)) {
|
||||
forgeDocBindShapeDrag(dom, elementId);
|
||||
} else {
|
||||
dom.setAttribute('draggable', 'true');
|
||||
dom.addEventListener('dragstart', (e) => {
|
||||
e.dataTransfer.setData('text/forge-doc-move', String(elementId));
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
});
|
||||
}
|
||||
dom.setAttribute('draggable', 'true');
|
||||
dom.addEventListener('dragstart', (e) => {
|
||||
e.dataTransfer.setData('text/forge-doc-move', String(elementId));
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
});
|
||||
});
|
||||
forgeDocInitQuizPlayers();
|
||||
forgeDocInitAssociationPlayers();
|
||||
@@ -1625,37 +1518,6 @@ function forgeDocRenderTextProps(panel, el) {
|
||||
});
|
||||
}
|
||||
|
||||
function forgeDocRenderShapeProps(panel, el) {
|
||||
const a = el.attributes;
|
||||
panel.innerHTML = `
|
||||
${forgeDocPropsHeader('forme')}
|
||||
<div class="docField"><label for="docShapeLabel">Libellé</label><input type="text" id="docShapeLabel" value="${a.label || ''}"></div>
|
||||
<div class="docFieldRow"><label for="docShapeX">Position X</label><input type="number" id="docShapeX" value="${a.x}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeY">Position Y</label><input type="number" id="docShapeY" value="${a.y}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeWidth">Largeur</label><input type="number" id="docShapeWidth" value="${a.width}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeHeight">Hauteur</label><input type="number" id="docShapeHeight" value="${a.height}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeRotation">Rotation (°)</label><input type="number" id="docShapeRotation" value="${a.rotation}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeZ">Ordre (z-index)</label><input type="number" id="docShapeZ" value="${a.z_index}" style="width:90px;"></div>
|
||||
<div class="docFieldRow"><label for="docShapeFill">Couleur de remplissage</label><input type="color" id="docShapeFill" value="${a.fill}"></div>
|
||||
<div class="docFieldRow"><label for="docShapeStroke">Couleur de bordure</label><input type="color" id="docShapeStroke" value="${a.stroke}"></div>
|
||||
<div class="docFieldRow"><label for="docShapeStrokeWidth">Épaisseur de bordure</label><input type="number" id="docShapeStrokeWidth" value="${a.stroke_width}" style="width:90px;"></div>
|
||||
${forgeDocDeleteButtonHtml()}
|
||||
`;
|
||||
|
||||
function patch(partial) { forgeDocUpdateAttributes(el.id, { ...el.attributes, ...partial }); }
|
||||
|
||||
document.getElementById('docShapeLabel').addEventListener('change', (e) => patch({ label: e.target.value }));
|
||||
document.getElementById('docShapeX').addEventListener('change', (e) => patch({ x: Number(e.target.value) }));
|
||||
document.getElementById('docShapeY').addEventListener('change', (e) => patch({ y: Number(e.target.value) }));
|
||||
document.getElementById('docShapeWidth').addEventListener('change', (e) => patch({ width: Number(e.target.value) }));
|
||||
document.getElementById('docShapeHeight').addEventListener('change', (e) => patch({ height: Number(e.target.value) }));
|
||||
document.getElementById('docShapeRotation').addEventListener('change', (e) => patch({ rotation: Number(e.target.value) }));
|
||||
document.getElementById('docShapeZ').addEventListener('change', (e) => patch({ z_index: Number(e.target.value) }));
|
||||
document.getElementById('docShapeFill').addEventListener('input', (e) => patch({ fill: e.target.value }));
|
||||
document.getElementById('docShapeStroke').addEventListener('input', (e) => patch({ stroke: e.target.value }));
|
||||
document.getElementById('docShapeStrokeWidth').addEventListener('change', (e) => patch({ stroke_width: Number(e.target.value) }));
|
||||
}
|
||||
|
||||
function forgeDocRenderImageProps(panel, el) {
|
||||
const a = el.attributes;
|
||||
panel.innerHTML = `
|
||||
@@ -2254,8 +2116,7 @@ function forgeDocRenderScenarioProps(panel, el) {
|
||||
* (retour utilisateur du 21/09/2026 : "passons à un véritable graphe
|
||||
* visuel", remplace la première version en liste de nœuds + menus
|
||||
* déroulants). Les nœuds sont des cartes positionnées/déplaçables à la
|
||||
* souris (glisser, comme les formes libres du canevas — voir
|
||||
* forgeDocBindShapeDrag) ; les choix qui ont une destination sont
|
||||
* souris (glisser) ; les choix qui ont une destination sont
|
||||
* dessinés comme des flèches SVG reliant les deux nœuds, étiquetées par
|
||||
* le texte du choix. Sélectionner un nœud (clic) ouvre son formulaire
|
||||
* d'édition (texte + choix) dans l'inspecteur (colonne de droite) —
|
||||
@@ -2268,7 +2129,7 @@ function forgeDocRenderScenarioProps(panel, el) {
|
||||
* pourrait diverger de ce que sanitize_scenario_config a réellement
|
||||
* accepté — SAUF la position pendant un glisser, mise à jour localement
|
||||
* en continu pour rester fluide, et persistée en un seul appel au
|
||||
* relâchement de la souris (même principe que forgeDocBindShapeDrag).
|
||||
* relâchement de la souris.
|
||||
* ------------------------------------------------------------------- */
|
||||
|
||||
let forgeDocScenarioGraphState = null;
|
||||
@@ -2737,7 +2598,6 @@ function forgeDocRenderProps(el) {
|
||||
return;
|
||||
}
|
||||
if (el.kind === 'titre' || el.kind === 'paragraphe') forgeDocRenderTextProps(panel, el);
|
||||
else if (forgeDocIsShapeKind(el.kind)) forgeDocRenderShapeProps(panel, el);
|
||||
else if (el.kind === 'image') forgeDocRenderImageProps(panel, el);
|
||||
else if (el.kind === 'bouton') forgeDocRenderButtonProps(panel, el);
|
||||
else if (el.kind === 'row') forgeDocRenderRowProps(panel, el);
|
||||
@@ -2869,37 +2729,23 @@ function forgeDocInit() {
|
||||
const root = document.getElementById('docEditor3');
|
||||
if (!root || !window.FORGE_DOCUMENT) return;
|
||||
|
||||
// Capturé AVANT window.forgeDocState (qui n'existe pas encore) : le
|
||||
// contenu initial de chaque vignette miniature vient du HTML déjà
|
||||
// rendu par le serveur (voir routes/document/document_edit.py::
|
||||
// rendered_pages, templates/document/document_edit.html), jamais
|
||||
// redemandé en AJAX au chargement — seul un futur forgeDocRenderPageTabs
|
||||
// (qui reconstruit #docPageTabs depuis ce cache) en a besoin.
|
||||
const initialPageThumbsHtml = {};
|
||||
document.querySelectorAll('.docPageThumbInner[data-page-id]').forEach((el) => {
|
||||
initialPageThumbsHtml[Number(el.dataset.pageId)] = el.innerHTML;
|
||||
});
|
||||
|
||||
window.forgeDocState = {
|
||||
slug: window.FORGE_DOCUMENT.slug,
|
||||
elements: window.FORGE_DOCUMENT.elements,
|
||||
elementsById: {},
|
||||
pages: window.FORGE_DOCUMENT.pages,
|
||||
activePageId: window.FORGE_DOCUMENT.activePageId,
|
||||
pageThumbsHtml: initialPageThumbsHtml,
|
||||
selectedId: null,
|
||||
undoStack: [],
|
||||
redoStack: [],
|
||||
previewMode: false,
|
||||
zoom: 100,
|
||||
shapeDrag: null,
|
||||
};
|
||||
forgeDocRebuildIndex();
|
||||
|
||||
forgeDocBindCanvasInteractions();
|
||||
forgeDocBindLibraryDragHandlers();
|
||||
forgeDocBindCanvasDropZone();
|
||||
forgeDocBindShapeDragGlobalHandlers();
|
||||
forgeDocBindDeselectOnBackgroundClick();
|
||||
forgeDocBindZoom();
|
||||
forgeDocBindWidthPicker();
|
||||
@@ -2908,8 +2754,7 @@ function forgeDocInit() {
|
||||
forgeDocBindMobileNav();
|
||||
forgeDocBindKeyboardShortcuts();
|
||||
forgeDocBindScenarioTreeModal();
|
||||
forgeDocRenderPageTabs();
|
||||
forgeDocBindPageTabsDrag();
|
||||
forgeDocRenderPageList();
|
||||
forgeDocBindPageNavPill();
|
||||
forgeDocUpdateHistoryButtons();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user