Remplace les onglets texte de pages par de vraies vignettes miniatures
Build and deploy / test-python (push) Successful in 7m23s
Build and deploy / test-js (push) Successful in 1m24s
Build and deploy / lint-python (push) Successful in 6m29s
Build and deploy / lint-js (push) Failing after 1m31s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 5m18s
Build and deploy / test-python (push) Successful in 7m23s
Build and deploy / test-js (push) Successful in 1m24s
Build and deploy / lint-python (push) Successful in 6m29s
Build and deploy / lint-js (push) Failing after 1m31s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 5m18s
Les vignettes réutilisent le HTML réellement rendu de chaque page (CSS scale trick) et sont centrées dans le conteneur du milieu, au lieu d'une barre pleine largeur. Corrige au passage deux bugs réels trouvés en écrivant les tests : - une page contenant un mini-jeu (bouton Suivant/Recommencer) cassait le parsing HTML car .docPageThumbCard était un <button> englobant un autre <button> ; passage en div role="button" + équivalent clavier, contenu copié rendu inert. - le renommage d'une page par double-clic ne fonctionnait plus du tout (sélecteur .docPageTab oublié lors du renommage des classes). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ecd483f352
commit
57c4de3d8a
@@ -366,7 +366,8 @@ body.objectEditBody > main.content {
|
||||
padding: 36px 40px;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -1212,102 +1213,157 @@ img.docImage {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ---- Bande d'onglets des PAGES (au-dessus du canevas, jamais un
|
||||
panneau latéral — voir retour utilisateur du 21/09/2026). Masquée en
|
||||
Mode Aperçu (voir la règle .docEditor3--preview plus bas), qui a sa
|
||||
propre navigation via .docPageNavPill ci-dessus. ---- */
|
||||
.docPageTabs {
|
||||
/* ---- Bande de VIGNETTES MINIATURES des pages, au-dessus de la page
|
||||
ET centrée dans le conteneur du milieu (.docCanvasArea, jamais toute
|
||||
la largeur de l'éditeur par-dessus les panneaux latéraux — retour
|
||||
utilisateur du 21/09/2026 : "je préfère avoir des miniatures ...
|
||||
centré dans le conteneur du milieu"). Chaque vignette affiche un
|
||||
VRAI rendu réduit du contenu de sa page (voir .docPageThumbInner plus
|
||||
bas, et rendered_pages côté serveur dans routes/document/
|
||||
document_edit.py) — jamais une carte générique numéro/titre. Masquée
|
||||
en Mode Aperçu (voir la règle .docEditor3--preview plus bas), qui a
|
||||
sa propre navigation via .docPageNavPill ci-dessus. ---- */
|
||||
.docPageThumbs {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 8px 20px 0;
|
||||
background: var(--doc-bg-2);
|
||||
border-bottom: 1px solid var(--doc-border);
|
||||
overflow-x: auto;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
padding: 4px 20px 28px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.docPageTab {
|
||||
.docPageThumbCard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 7px 10px 7px 14px;
|
||||
border: 1px solid var(--doc-border);
|
||||
border-bottom: none;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background: transparent;
|
||||
color: var(--doc-muted);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.docPageTab:hover {
|
||||
color: var(--doc-text);
|
||||
border-color: var(--doc-accent);
|
||||
}
|
||||
|
||||
.docPageTab.is-active {
|
||||
background: var(--doc-bg);
|
||||
color: var(--doc-text);
|
||||
}
|
||||
|
||||
.docPageTab.is-dragging {
|
||||
.docPageThumbCard.is-dragging {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.docPageTabTitle {
|
||||
max-width: 160px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.docPageThumbCard:focus-visible {
|
||||
outline: 2px solid var(--doc-accent);
|
||||
outline-offset: 2px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.docPageTabTitle[contenteditable="true"] {
|
||||
.docPageThumbFrame {
|
||||
/* <span> (jamais <div>, invalide comme enfant direct d'un <button> —
|
||||
voir templates/document/document_edit.html) : display:block requis
|
||||
pour que width/aspect-ratio s'appliquent normalement. */
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 132px;
|
||||
aspect-ratio: 4 / 3;
|
||||
border: 2px solid var(--doc-border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
background: var(--doc-card);
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
transition: border-color 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.docPageThumbCard:hover .docPageThumbFrame {
|
||||
border-color: var(--doc-accent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.docPageThumbCard.is-active .docPageThumbFrame {
|
||||
border-color: var(--doc-accent);
|
||||
box-shadow: 0 0 0 2px var(--doc-accent);
|
||||
}
|
||||
|
||||
/* Astuce "scale inverse" pour une vraie vignette : le contenu est rendu
|
||||
à sa largeur RÉELLE (voir .docPage, 760px) puis réduit visuellement —
|
||||
jamais un second moteur de rendu séparé pour les miniatures, c'est le
|
||||
MÊME rendu que le canevas principal, juste redimensionné en CSS. Le
|
||||
cadre (.docPageThumbFrame) le rogne verticalement s'il dépasse — un
|
||||
support de formation "page" est proche d'un format diapositive, ce
|
||||
recadrage reste représentatif. */
|
||||
.docPageThumbInner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 760px;
|
||||
transform: scale(0.1737);
|
||||
transform-origin: top left;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.docPageThumbDelete {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: rgb(11 14 20 / 65%);
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.docPageThumbCard:hover .docPageThumbDelete {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.docPageThumbDelete:hover {
|
||||
background: var(--doc-quiz-danger-border);
|
||||
}
|
||||
|
||||
.docPageThumbs.docPageTabs--single .docPageThumbDelete {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.docPageThumbLabel {
|
||||
max-width: 132px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--doc-muted);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.docPageThumbCard.is-active .docPageThumbLabel {
|
||||
color: var(--doc-text);
|
||||
}
|
||||
|
||||
.docPageThumbLabel[contenteditable="true"] {
|
||||
outline: none;
|
||||
border-bottom: 1px solid var(--doc-accent);
|
||||
cursor: text;
|
||||
user-select: text;
|
||||
color: var(--doc-text);
|
||||
}
|
||||
|
||||
.docPageTabDelete {
|
||||
.docPageThumbAddCard .docPageThumbFrame {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
border-style: dashed;
|
||||
color: var(--doc-muted);
|
||||
}
|
||||
|
||||
.docPageTabDelete:hover {
|
||||
background: var(--doc-quiz-danger-bg);
|
||||
color: var(--doc-quiz-danger-text);
|
||||
}
|
||||
|
||||
.docPageTabs.docPageTabs--single .docPageTabDelete {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.docPageTabAdd {
|
||||
flex-shrink: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 8px;
|
||||
border: 1px dashed var(--doc-border);
|
||||
background: transparent;
|
||||
color: var(--doc-muted);
|
||||
font-size: 16px;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.docPageTabAdd:hover {
|
||||
.docPageThumbAddCard:hover .docPageThumbFrame {
|
||||
color: var(--doc-text);
|
||||
border-color: var(--doc-accent);
|
||||
}
|
||||
|
||||
/* ---- RIGHT SIDEBAR : Propriétés ---- */
|
||||
@@ -1551,7 +1607,7 @@ img.docImage {
|
||||
.docEditor3.docEditor3--preview .docSidebarRight,
|
||||
.docEditor3.docEditor3--preview .docBottomNav,
|
||||
.docEditor3.docEditor3--preview .docZoomPill,
|
||||
.docEditor3.docEditor3--preview .docPageTabs {
|
||||
.docEditor3.docEditor3--preview .docPageThumbs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,15 @@ 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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -485,6 +494,11 @@ 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);
|
||||
});
|
||||
}
|
||||
@@ -508,6 +522,7 @@ 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);
|
||||
}
|
||||
@@ -525,7 +540,7 @@ function forgeDocSelectAllText(el) {
|
||||
}
|
||||
|
||||
function forgeDocStartRenamingPageTab(titleEl) {
|
||||
const tab = titleEl.closest('.docPageTab');
|
||||
const tab = titleEl.closest('.docPageThumbCard');
|
||||
const pageId = Number(tab.dataset.pageId);
|
||||
const original = titleEl.textContent;
|
||||
titleEl.setAttribute('contenteditable', 'true');
|
||||
@@ -568,30 +583,52 @@ function forgeDocRenderPageTabs() {
|
||||
if (!container) return;
|
||||
const pages = forgeDocOrderedPages();
|
||||
container.classList.toggle('docPageTabs--single', pages.length <= 1);
|
||||
const tabsHtml = pages.map((p) => `
|
||||
<button type="button"
|
||||
class="docPageTab ${p.id === window.forgeDocState.activePageId ? 'is-active' : ''}"
|
||||
data-page-id="${p.id}"
|
||||
draggable="true">
|
||||
<span class="docPageTabTitle">${forgeDocEscapeHtml(p.title)}</span>
|
||||
<span class="docPageTabDelete" data-page-id="${p.id}" title="Supprimer cette page">✕</span>
|
||||
</button>
|
||||
// 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' : ''}"
|
||||
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>
|
||||
</div>
|
||||
`).join('');
|
||||
container.innerHTML = `${tabsHtml}<button type="button" class="docPageTabAdd" id="docPageTabAdd" aria-label="Ajouter une page" title="Ajouter une page">+</button>`;
|
||||
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('.docPageTab').forEach((tab) => {
|
||||
tab.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('docPageTabDelete')) return;
|
||||
forgeDocSwitchPage(Number(tab.dataset.pageId));
|
||||
container.querySelectorAll('.docPageThumbCard[data-page-id]').forEach((card) => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('docPageThumbDelete')) return;
|
||||
forgeDocSwitchPage(Number(card.dataset.pageId));
|
||||
});
|
||||
card.addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'Enter' && e.key !== ' ') return;
|
||||
e.preventDefault();
|
||||
forgeDocSwitchPage(Number(card.dataset.pageId));
|
||||
});
|
||||
});
|
||||
container.querySelectorAll('.docPageTabTitle').forEach((titleEl) => {
|
||||
titleEl.addEventListener('dblclick', (e) => {
|
||||
container.querySelectorAll('.docPageThumbLabel').forEach((labelEl) => {
|
||||
labelEl.addEventListener('dblclick', (e) => {
|
||||
e.stopPropagation();
|
||||
forgeDocStartRenamingPageTab(titleEl);
|
||||
forgeDocStartRenamingPageTab(labelEl);
|
||||
});
|
||||
});
|
||||
container.querySelectorAll('.docPageTabDelete').forEach((btn) => {
|
||||
container.querySelectorAll('.docPageThumbDelete').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
forgeDocDeletePage(Number(btn.dataset.pageId));
|
||||
@@ -601,22 +638,22 @@ function forgeDocRenderPageTabs() {
|
||||
}
|
||||
|
||||
function forgeDocBindPageTabsDrag() {
|
||||
// Délégation sur le CONTENEUR (jamais les onglets eux-mêmes, recréés à
|
||||
// chaque forgeDocRenderPageTabs) : un seul jeu de listeners pour toute
|
||||
// la session, même principe que forgeDocMotsBindGlobalMouseup.
|
||||
// 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 tab = e.target.closest('.docPageTab');
|
||||
if (!tab) return;
|
||||
draggedId = Number(tab.dataset.pageId);
|
||||
tab.classList.add('is-dragging');
|
||||
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 tab = e.target.closest('.docPageTab');
|
||||
if (tab) tab.classList.remove('is-dragging');
|
||||
const card = e.target.closest('.docPageThumbCard');
|
||||
if (card) card.classList.remove('is-dragging');
|
||||
});
|
||||
container.addEventListener('dragover', (e) => {
|
||||
if (draggedId !== null) e.preventDefault();
|
||||
@@ -624,10 +661,10 @@ function forgeDocBindPageTabsDrag() {
|
||||
container.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
if (draggedId === null) return;
|
||||
const targetTab = e.target.closest('.docPageTab');
|
||||
const targetCard = e.target.closest('.docPageThumbCard[data-page-id]');
|
||||
const ordered = forgeDocOrderedPages();
|
||||
const newIndex = targetTab
|
||||
? ordered.findIndex((p) => p.id === Number(targetTab.dataset.pageId))
|
||||
const newIndex = targetCard
|
||||
? ordered.findIndex((p) => p.id === Number(targetCard.dataset.pageId))
|
||||
: ordered.length - 1;
|
||||
const movedId = draggedId;
|
||||
draggedId = null;
|
||||
@@ -845,7 +882,7 @@ function forgeDocQuizPlayerRestart(playerEl, state) {
|
||||
}
|
||||
|
||||
function forgeDocInitQuizPlayers() {
|
||||
document.querySelectorAll('.docQuizPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docQuizPlayer').forEach((playerEl) => {
|
||||
const questions = forgeDocQuizPlayerQuestions(playerEl);
|
||||
if (!questions.length) return;
|
||||
const state = {
|
||||
@@ -997,7 +1034,7 @@ function forgeDocAssociationRestart(playerEl) {
|
||||
}
|
||||
|
||||
function forgeDocInitAssociationPlayers() {
|
||||
document.querySelectorAll('.docAssocPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docAssocPlayer').forEach((playerEl) => {
|
||||
const data = forgeDocAssociationPlayerData(playerEl);
|
||||
if (!data.left.length) return;
|
||||
forgeDocAssociationRestart(playerEl);
|
||||
@@ -1162,7 +1199,7 @@ function forgeDocMemoryRestart(playerEl) {
|
||||
}
|
||||
|
||||
function forgeDocInitMemoryPlayers() {
|
||||
document.querySelectorAll('.docMemoryPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docMemoryPlayer').forEach((playerEl) => {
|
||||
const data = forgeDocMemoryPlayerData(playerEl);
|
||||
if (!data.cards.length) return;
|
||||
forgeDocMemoryRestart(playerEl);
|
||||
@@ -1301,7 +1338,7 @@ function forgeDocMotsBindGlobalMouseup() {
|
||||
if (forgeDocMotsGlobalMouseupBound) return;
|
||||
forgeDocMotsGlobalMouseupBound = true;
|
||||
document.addEventListener('mouseup', () => {
|
||||
document.querySelectorAll('.docMotsPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docMotsPlayer').forEach((playerEl) => {
|
||||
const state = playerEl.forgeDocMotsState;
|
||||
if (state && state.dragging) forgeDocMotsFinishSelection(playerEl, state);
|
||||
});
|
||||
@@ -1381,7 +1418,7 @@ function forgeDocMotsRestart(playerEl) {
|
||||
|
||||
function forgeDocInitMotsPlayers() {
|
||||
forgeDocMotsBindGlobalMouseup();
|
||||
document.querySelectorAll('.docMotsPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docMotsPlayer').forEach((playerEl) => {
|
||||
const data = forgeDocMotsPlayerData(playerEl);
|
||||
if (!data.words.length) return;
|
||||
forgeDocMotsRestart(playerEl);
|
||||
@@ -1494,7 +1531,7 @@ function forgeDocScenarioRestart(playerEl, state) {
|
||||
}
|
||||
|
||||
function forgeDocInitScenarioPlayers() {
|
||||
document.querySelectorAll('.docScenarioPlayer').forEach((playerEl) => {
|
||||
document.querySelectorAll('#docPage .docScenarioPlayer').forEach((playerEl) => {
|
||||
const scenarios = forgeDocScenarioPlayerData(playerEl);
|
||||
if (!scenarios.length || !scenarios[0].nodes || !scenarios[0].nodes.length) return;
|
||||
const state = { current: 0, scenarios, currentNodeId: scenarios[0].nodes[0].id };
|
||||
@@ -2832,12 +2869,24 @@ 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: [],
|
||||
|
||||
Reference in New Issue
Block a user