Corrige le clignotement de la boîte de dialogue entière au lieu du seul texte

Suite du correctif précédent (124f250, marqueur "dataBound") : le
rafraîchissement fonctionnait, mais remplaçait tout l'élément de PREMIER
NIVEAU marqué — pour un Texte "Donnée liée" posé DANS un élément de jeu
réutilisable (ex. une boîte de dialogue), le seul élément de premier
niveau existant est l'EXEMPLAIRE lui-même (ses descendants internes ne
sont jamais des entrées séparées de la scène, voir list_elements.py) :
tout l'exemplaire — voile plein écran, boîte, tout — était donc remplacé
d'un bloc, ce qui le faisait visuellement disparaître puis réapparaître
pour un simple changement de texte à l'intérieur.

Correctif (templates/play.html, refreshRuntimeData()) : avant de
remplacer un élément marqué en bloc, on cherche d'abord, DANS le nouveau
fragment, des descendants plus précis portant eux-mêmes un marqueur en
commentaire ("visibilityGated"/"dataBound" — jamais "repeaterItem"/
"jaugeBar", qui restent volontairement régénérés en bloc, un
comportement déjà correct pour un Répéteur/une Jauge). S'il en existe,
seuls CES éléments précis sont patchés individuellement (retrouvés via
leur propre data-element-id) ; sinon, comportement inchangé (remplace
l'élément entier, cas normal d'un Texte "Donnée liée" posé directement
sur une scène, hors élément de jeu réutilisable).

155 tests toujours au vert (changement purement côté client — le
rendu serveur et la présence du marqueur, eux, étaient déjà couverts par
les tests du commit précédent). Vérifié structurellement (adjacence
</p><!--dataBound--> confirmée dans le rendu réel du projet "test").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-08-28 09:58:50 +02:00
co-authored by Claude Sonnet 5
parent 124f250d2b
commit ed4dd78dad
+42 -1
View File
@@ -584,6 +584,31 @@
} }
return false; return false;
} }
// "visibilityGated"/"dataBound" sont posés comme un COMMENTAIRE
// HTML juste après la balise concernée (voir _mark() dans
// render_element_html.py) — jamais comme une classe CSS, à la
// différence de "repeaterItem"/"jaugeBar" (qui, eux, désignent
// un widget à régénérer EN BLOC, lignes/valeur comprises, un
// comportement déjà correct pour ces deux-là). Repérer ce
// commentaire permet de retrouver, à l'intérieur d'un fragment
// fraîchement rendu, l'élément PRÉCIS qui a changé — même s'il
// est niché dans un exemplaire d'élément de jeu réutilisable
// (ex. un Texte "Donnée liée" à l'intérieur d'une boîte de
// dialogue), où lui seul porte l'attribut data-element-id qui
// l'identifie, son marqueur ne remontant jusqu'au SEUL élément
// de premier niveau existant (l'exemplaire) que parce que son
// HTML est imbriqué dans le sien.
const COMMENT_MARKERS = ['visibilityGated', 'dataBound'];
function findCommentMarkedDescendants(root) {
const found = [];
root.querySelectorAll('[data-element-id]').forEach(function(node) {
const sib = node.nextSibling;
if (sib && sib.nodeType === Node.COMMENT_NODE && COMMENT_MARKERS.indexOf(sib.data) !== -1) {
found.push(node);
}
});
return found;
}
const markedCandidates = screenData.elements.filter(hasMarker); const markedCandidates = screenData.elements.filter(hasMarker);
markedCandidates.filter(function(e) { markedCandidates.filter(function(e) {
return !markedCandidates.some(function(other) { return other.id !== e.id && isDescendantOf(other, e.id); }); return !markedCandidates.some(function(other) { return other.id !== e.id && isDescendantOf(other, e.id); });
@@ -593,7 +618,23 @@
const container = document.createElement('div'); const container = document.createElement('div');
container.innerHTML = el.rendered_html; container.innerHTML = el.rendered_html;
const newNode = container.firstElementChild; const newNode = container.firstElementChild;
if (newNode) target.replaceWith(newNode); if (!newNode) return;
const innerMarked = findCommentMarkedDescendants(newNode);
if (innerMarked.length) {
// Des éléments plus précis existent À L'INTÉRIEUR (ex. un
// Texte "Donnée liée" posé dans un élément de jeu
// réutilisable) : on ne patche QUE ceux-là, en préservant
// tout le reste — une boîte de dialogue ne doit ni
// disparaître ni réapparaître juste parce qu'un texte à
// l'intérieur a changé.
innerMarked.forEach(function(innerNode) {
const innerId = innerNode.getAttribute('data-element-id');
const liveInner = target.querySelector('[data-element-id="' + innerId + '"]');
if (liveInner) liveInner.replaceWith(innerNode);
});
} else {
target.replaceWith(newNode);
}
}); });
applyOpenRowBindings(); applyOpenRowBindings();
} catch (err) { } catch (err) {