From ca7daf9a31d99234ce6cfb98e51e0f10d37e370a Mon Sep 17 00:00:00 2001 From: william Date: Wed, 26 Aug 2026 07:47:19 +0200 Subject: [PATCH] =?UTF-8?q?R=C3=A9attache=20toujours=20les=20gestionnaires?= =?UTF-8?q?=20de=20clic=20apr=C3=A8s=20un=20rafra=C3=AEchissement=20de=20d?= =?UTF-8?q?onn=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test de diagnostic déterminant : après le blocage rapporté (plus aucune ligne de Répéteur ne répond après le tout premier clic), appeler manuellement bindClicks() dans la console suffisait à tout réparer — donc ni le DOM ni le graphe de logique n'étaient en cause, seule l'INVOCATION de bindClicks() manquait à un moment donné. Cause : refreshRuntimeData() faisait un retour anticipé silencieux (`if (!screenData || !screenDiv) return;`) qui sautait, avec lui, TOUT le reste de la fonction — y compris bindClicks(), bindHoverTexts() et bindHoverTriggers() — sans le moindre message d'erreur, laissant les éléments régénérés (Répéteur compris) sans aucun écouteur pour le reste de la partie. Fix : ce garde-fou ne protège plus désormais que le bloc de régénération du contenu de l'écran (qui a effectivement besoin de screenData/ screenDiv) ; les réattachements, eux, s'exécutent toujours ensuite, quoi qu'il arrive. Un try/catch autour de la régénération ajoute en prime un filet de sécurité : toute erreur inattendue s'y loggera clairement au lieu de bloquer silencieusement le reste, si jamais ce n'était pas l'unique cause. Co-Authored-By: Claude Sonnet 5 --- templates/play.html | 48 +++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/templates/play.html b/templates/play.html index 1fce822e..f6945494 100644 --- a/templates/play.html +++ b/templates/play.html @@ -411,21 +411,39 @@ screensData = gameData.screens; const screenData = screensData.find(s => s.id === window.currentScreenId); const screenDiv = document.querySelector('.playScreen[data-screen-id="' + window.currentScreenId + '"]'); - if (!screenData || !screenDiv) return; - screenData.elements.filter(function(e){ return !e.parent_id; }).forEach(function(el) { - if (!el.rendered_html) return; - // "repeaterItem" (liste de données), "jaugeBar" (2.1 — jauge liée - // à une donnée) et "visibilityGated" (condition de visibilité — - // voir render_element_html.py) sont les types d'éléments dont le - // contenu/l'affichage dépend de la donnée elle-même plutôt que - // d'une action "Modifier un élément" posée à la main dans le - // graphe — eux seuls doivent être régénérés après un changement - // de donnée ou de variable. - if (el.rendered_html.indexOf('repeaterItem') === -1 && el.rendered_html.indexOf('jaugeBar') === -1 && el.rendered_html.indexOf('visibilityGated') === -1) return; - const wrapper = screenDiv.querySelector('.playElement[data-el-id="' + el.id + '"] .playElementInner'); - if (wrapper) wrapper.innerHTML = el.rendered_html; - }); - applyOpenRowBindings(); + // Le bloc ci-dessous (régénération du contenu de l'écran courant) + // est sauté si l'écran n'est pas trouvé, mais bindClicks() et les + // autres réattachements juste après ne doivent JAMAIS dépendre de + // cette condition : un retour anticipé ici a déjà laissé, dans la + // pratique, un Répéteur fraîchement régénéré sans AUCUN gestionnaire + // de clic pour le reste de la partie (plus aucune ligne ne + // répondait, silencieusement, sans erreur) — ces fonctions sont sans + // risque à rappeler même quand rien n'a changé. + if (screenData && screenDiv) { + // try/catch : une erreur inattendue pendant la régénération (ex. + // structure de données imprévue) ne doit jamais empêcher les + // réattachements ci-dessous de s'exécuter — sinon le Répéteur (ou + // tout autre élément cliquable) reste silencieusement inerte pour + // le reste de la partie, sans le moindre message d'erreur visible. + try { + screenData.elements.filter(function(e){ return !e.parent_id; }).forEach(function(el) { + if (!el.rendered_html) return; + // "repeaterItem" (liste de données), "jaugeBar" (2.1 — jauge liée + // à une donnée) et "visibilityGated" (condition de visibilité — + // voir render_element_html.py) sont les types d'éléments dont le + // contenu/l'affichage dépend de la donnée elle-même plutôt que + // d'une action "Modifier un élément" posée à la main dans le + // graphe — eux seuls doivent être régénérés après un changement + // de donnée ou de variable. + if (el.rendered_html.indexOf('repeaterItem') === -1 && el.rendered_html.indexOf('jaugeBar') === -1 && el.rendered_html.indexOf('visibilityGated') === -1) return; + const wrapper = screenDiv.querySelector('.playElement[data-el-id="' + el.id + '"] .playElementInner'); + if (wrapper) wrapper.innerHTML = el.rendered_html; + }); + applyOpenRowBindings(); + } catch (err) { + console.error('refreshRuntimeData: erreur pendant la régénération de l\'écran', err); + } + } bindClicks(); bindHoverTexts(); bindHoverTriggers();