diff --git a/templates/play.html b/templates/play.html index 69369ca4..7e611467 100644 --- a/templates/play.html +++ b/templates/play.html @@ -351,26 +351,33 @@ // rechargement de page (flash à vide) à chaque clic sur une ligne. // // Parmi les éléments qui ont un {{champ}} non résolu, on ne garde que - // les plus "hauts" dans l'arbre : si un ancêtre ET un de ses - // descendants sont tous deux candidats, seul l'ancêtre est régénéré - // (son rendered_html inclut déjà ce descendant) — sans ce filtre, le - // descendant serait régénéré deux fois, la 2e fois à partir du DOM déjà - // à jour de la 1re passe. + // les plus SPÉCIFIQUES (les plus profonds) : si un élément ET l'un de + // ses DESCENDANTS sont tous deux candidats, seul le descendant est + // régénéré (rendered_html d'un conteneur inclut TOUJOURS celui de ses + // descendants, donc un conteneur "candidat" ne l'est souvent que parce + // qu'un descendant à lui l'est — le garder en plus regénérerait + // inutilement tout son sous-arbre, à l'exact opposé du but recherché). + // ATTENTION : la version précédente de ce filtre vérifiait l'inverse + // (exclure un élément si un ANCÊTRE est candidat) — comme un ancêtre + // est presque toujours "candidat" dès qu'un descendant l'est (son HTML + // le contient), ce filtre ne gardait en pratique QUE l'ancêtre racine + // de l'écran, annulant complètement l'effet recherché par ce correctif. const byId = {}; screenData.elements.forEach(function(e){ byId[e.id] = e; }); function hasUnresolvedPlaceholder(e) { return !!(e.rendered_html && e.rendered_html.indexOf(PLACEHOLDER_OPEN) !== -1); } - function hasCandidateAncestor(e) { + function isDescendantOf(e, ancestorId) { let p = e.parent_id ? byId[e.parent_id] : null; while (p) { - if (hasUnresolvedPlaceholder(p)) return true; + if (p.id === ancestorId) return true; p = p.parent_id ? byId[p.parent_id] : null; } return false; } - const targets = screenData.elements.filter(function(e) { - return hasUnresolvedPlaceholder(e) && !hasCandidateAncestor(e); + const candidates = screenData.elements.filter(hasUnresolvedPlaceholder); + const targets = candidates.filter(function(e) { + return !candidates.some(function(other) { return other.id !== e.id && isDescendantOf(other, e.id); }); }); targets.forEach(function(el) { @@ -480,25 +487,33 @@ // qui portait le marqueur (le Répéteur imbriqué à l'intérieur) // et se retrouvait régénéré en entier à sa place — potentiellement // l'écran entier (jauges, onglets... compris) s'il n'y avait - // qu'un seul gros conteneur racine. Comme pour - // applyOpenRowBindings(), on ne garde que les éléments marqués - // les plus "hauts" dans l'arbre, pour ne jamais régénérer un même - // nœud deux fois. + // qu'un seul gros conteneur racine. + // + // Parmi les éléments marqués, on ne garde que les plus + // SPÉCIFIQUES (les plus profonds) : un ancêtre est presque + // toujours "marqué" lui aussi dès qu'un descendant l'est, puisque + // son rendered_html contient celui de ses descendants — le + // garder EN PLUS régénérerait tout son sous-arbre pour rien. + // (Une version antérieure de ce filtre vérifiait l'inverse — + // exclure un élément si un ANCÊTRE est marqué — ce qui ne + // gardait en pratique que l'ancêtre racine de l'écran et + // annulait complètement l'effet recherché.) const byId = {}; screenData.elements.forEach(function(e){ byId[e.id] = e; }); function hasMarker(e) { return !!(e.rendered_html && (e.rendered_html.indexOf('repeaterItem') !== -1 || e.rendered_html.indexOf('jaugeBar') !== -1 || e.rendered_html.indexOf('visibilityGated') !== -1)); } - function hasMarkedAncestor(e) { + function isDescendantOf(e, ancestorId) { let p = e.parent_id ? byId[e.parent_id] : null; while (p) { - if (hasMarker(p)) return true; + if (p.id === ancestorId) return true; p = p.parent_id ? byId[p.parent_id] : null; } return false; } - screenData.elements.filter(function(e) { - return hasMarker(e) && !hasMarkedAncestor(e); + const markedCandidates = screenData.elements.filter(hasMarker); + markedCandidates.filter(function(e) { + return !markedCandidates.some(function(other) { return other.id !== e.id && isDescendantOf(other, e.id); }); }).forEach(function(el) { const target = screenDiv.querySelector('[data-element-id="' + el.id + '"]'); if (!target) return;