From c04a81cfec0058307aa52b67e787cdefc8e95af7 Mon Sep 17 00:00:00 2001 From: william Date: Sun, 20 Sep 2026 17:10:56 +0200 Subject: [PATCH] La consequence du Scenario remplace la situation, pas un feedback Quiz Retour utilisateur : "ce n'est pas un quiz, la consequence s'affiche a la place de la situation precedente". L'ancien design affichait la situation ET les choix en permanence avec un encart de feedback separe en dessous (calque sur le Quiz). Desormais un seul bloc de texte (.docScenarioSituation) sert successivement a la situation PUIS, une fois un choix fait, a la consequence a sa place ; les boutons de choix disparaissent avec elle. Supprime l'element .docScenarioConsequence devenu inutile. Verifie via simulation DOM reelle (jsdom) : la consequence remplace bien le texte de la situation (jamais affichee a cote), les choix disparaissent, le retour a une situation neutre au scenario suivant/au redemarrage fonctionne. Co-Authored-By: Claude Sonnet 5 --- .../rendering/render_document_element.py | 16 ++++++--- document_engine/rendering/rendering.md | 21 ++++++----- static/document/js/document-editor.js | 36 ++++++++++--------- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/document_engine/rendering/render_document_element.py b/document_engine/rendering/render_document_element.py index 1904c53b..4b87eb44 100644 --- a/document_engine/rendering/render_document_element.py +++ b/document_engine/rendering/render_document_element.py @@ -467,10 +467,17 @@ def _render_scenario_player(config: dict[str, Any]) -> str: scénarios gardent l'ORDRE d'écriture du créateur (contrairement à l'Association/Memory/Mots mêlés, jamais mélangés) : ce sont des mises en situation séquentielles, pas des éléments à faire correspondre ou - retrouver — un mélange n'aurait ici aucun sens pédagogique. Réutilise - les classes visuelles du Quiz (.docQuizOptions/.docQuizFeedback/ - .docQuizNextBar/.docQuizQuestionText) plutôt que de dupliquer ces - règles, même esprit que .docAssocCard/.docMinigameRestartBar.""" + retrouver — un mélange n'aurait ici aucun sens pédagogique. Un seul + bloc de texte (.docScenarioSituation) sert successivement à afficher + la situation PUIS, une fois un choix fait, la conséquence à sa place + (les boutons de choix disparaissent aussi) — volontairement PAS le + comportement du Quiz, où la question reste affichée à côté d'un + encart de feedback séparé (retour utilisateur du 20/09/2026 : "ce + n'est pas un quiz, la conséquence s'affiche à la place de la + situation précédente"). Réutilise les classes visuelles du Quiz + (.docQuizOptions/.docQuizFeedback/.docQuizNextBar/ + .docQuizQuestionText) plutôt que de dupliquer ces règles, même esprit + que .docAssocCard/.docMinigameRestartBar.""" config_json = html_lib.escape(json.dumps({"scenarios": config["scenarios"]}), quote=True) return ( f'
' @@ -479,7 +486,6 @@ def _render_scenario_player(config: dict[str, Any]) -> str: f'
' f'
' f'
' - f'
' f'
' f'' f"
" diff --git a/document_engine/rendering/rendering.md b/document_engine/rendering/rendering.md index 94bdb477..4e635d8d 100644 --- a/document_engine/rendering/rendering.md +++ b/document_engine/rendering/rendering.md @@ -102,14 +102,19 @@ regroupement à chaque appel. scénarios) — sanitizée (`sanitize_scenario_config`) avant lecture. Si au moins un scénario existe, s'y ajoute (fonction privée `_render_scenario_player`) la mise en situation RÉELLE et interactive : - l'apprenant lit la situation, choisit une option, découvre la - conséquence de SON choix et si c'était le bon, puis passe au scénario - suivant. Les scénarios gardent l'ORDRE d'écriture du créateur (jamais - mélangés, contrairement à Association/Memory/Mots mêlés — ce sont des - mises en situation séquentielles, pas des éléments à faire - correspondre/retrouver). Réutilise les classes visuelles du Quiz - (`.docQuizOptions`/`.docQuizFeedback`/`.docQuizNextBar`/ - `.docQuizQuestionText`) plutôt que de dupliquer ces règles. Embarqué en + l'apprenant lit la situation, choisit une option, puis la conséquence + de SON choix REMPLACE l'affichage de la situation (les boutons de + choix disparaissent avec elle) avant de passer au scénario suivant — + volontairement PAS le comportement du Quiz, où la question resterait + affichée à côté d'un encart de feedback séparé (retour utilisateur du + 20/09/2026 : "ce n'est pas un quiz, la conséquence s'affiche à la + place de la situation précédente"). Les scénarios gardent l'ORDRE + d'écriture du créateur (jamais mélangés, contrairement à + Association/Memory/Mots mêlés — ce sont des mises en situation + séquentielles, pas des éléments à faire correspondre/retrouver). + Réutilise les classes visuelles du Quiz (`.docQuizOptions`/ + `.docQuizFeedback`/`.docQuizNextBar`/`.docQuizQuestionText`) plutôt que + de dupliquer ces règles. Embarqué en JSON dans un attribut `data-scenario-config`, échappé pour l'HTML — même principe que les autres mini-jeux, aucun aller-retour serveur pendant qu'on joue. Comme l'Association/Memory/Mots mêlés (mais diff --git a/static/document/js/document-editor.js b/static/document/js/document-editor.js index ff6fda59..6b8d87b7 100644 --- a/static/document/js/document-editor.js +++ b/static/document/js/document-editor.js @@ -1163,14 +1163,15 @@ function forgeDocRenderScenarioPlayerScenario(playerEl, state) { const item = state.scenarios[state.current]; const situationEl = playerEl.querySelector('.docScenarioSituation'); const choicesEl = playerEl.querySelector('.docScenarioChoices'); - const consequenceEl = playerEl.querySelector('.docScenarioConsequence'); const progEl = playerEl.querySelector('.docScenarioProg'); const nextBtn = playerEl.querySelector('.docScenarioNextBtn'); + // Repart d'un bloc "situation" neutre (jamais un résidu des classes + // is-visible/is-ok/is-ko posées par une réponse précédente, voir + // forgeDocScenarioPlayerAnswer ci-dessous). + situationEl.className = 'docScenarioSituation docQuizQuestionText'; situationEl.textContent = item.situation; choicesEl.innerHTML = ''; - consequenceEl.className = 'docScenarioConsequence docQuizFeedback'; - consequenceEl.textContent = ''; nextBtn.classList.remove('is-visible'); playerEl.querySelector('.docMinigameRestartBar').classList.remove('is-visible'); item.choices.forEach((choice, idx) => { @@ -1180,30 +1181,31 @@ function forgeDocRenderScenarioPlayerScenario(playerEl, state) { btn.textContent = choice.text; btn.addEventListener('click', (e) => { e.stopPropagation(); - forgeDocScenarioPlayerAnswer(playerEl, state, idx, btn); + forgeDocScenarioPlayerAnswer(playerEl, state, idx); }); choicesEl.appendChild(btn); }); progEl.textContent = `Scénario ${state.current + 1} sur ${state.scenarios.length}`; } -function forgeDocScenarioPlayerAnswer(playerEl, state, idx, btn) { +function forgeDocScenarioPlayerAnswer(playerEl, state, idx) { if (state.answered) return; state.answered = true; const item = state.scenarios[state.current]; - const buttons = playerEl.querySelectorAll('.docScenarioChoice'); - buttons.forEach((b) => { b.disabled = true; }); - const consequenceEl = playerEl.querySelector('.docScenarioConsequence'); + const situationEl = playerEl.querySelector('.docScenarioSituation'); + const choicesEl = playerEl.querySelector('.docScenarioChoices'); const isLast = state.current === state.scenarios.length - 1; - if (idx === item.correct_index) { - btn.classList.add('is-correct'); - consequenceEl.classList.add('is-visible', 'is-ok'); - } else { - btn.classList.add('is-wrong'); - buttons[item.correct_index].classList.add('is-correct'); - consequenceEl.classList.add('is-visible', 'is-ko'); - } - consequenceEl.textContent = item.choices[idx].consequence || 'Aucune conséquence renseignée pour ce choix.'; + const isCorrect = idx === item.correct_index; + const consequenceText = item.choices[idx].consequence || 'Aucune conséquence renseignée pour ce choix.'; + + // Ce n'est pas un Quiz : la conséquence REMPLACE la situation (le récit + // avance), et les boutons de choix disparaissent avec elle — jamais un + // encart de feedback séparé pendant que la situation resterait affichée + // (retour utilisateur du 20/09/2026). + situationEl.className = `docScenarioSituation docQuizFeedback is-visible ${isCorrect ? 'is-ok' : 'is-ko'}`; + situationEl.textContent = consequenceText; + choicesEl.innerHTML = ''; + if (isLast) { playerEl.querySelector('.docMinigameRestartBar').classList.add('is-visible'); } else {