Deux fonctionnalités demandées, développées et corrigées dans cet
échange :
1. "Donnée liée" (Texte/Titre) : le réglage à 2 filtres fixes (toujours
combinés en ET) devient une liste de conditions ILLIMITÉE, avec un
choix ET/OU pour les combiner (screens/widgets/controls/c_clause_list.py,
screens/clause_list_codec.py). Rétrocompatible avec les anciens
éléments (_data_filtre_champ/_data_filtre2_champ), convertis à la
volée à la lecture, sans migration. Après un premier essai à la
présentation trop compacte et technique (retour utilisateur : "pas de
champ technique, pas de notation bizarre {{ }}"), la présentation
finale reprend EXACTEMENT l'ancien style (labels "Champ"/"...est"/
"...cette valeur", même sélecteur de valeur fixe/dynamique/variable
déjà existant, jamais la syntaxe brute), simplement répétée par
condition (templates/partials/clause_row.html), avec un bouton
"+ Ajouter une condition" bien visible et une liste scrollable
(static/style.css, .clauseListWrap). Le même moteur (filter_repeater_
rows.py généralisé) profite aussi au Répéteur de données en interne.
2. Nœud Condition de la Logique de la scène : peut désormais tester une
VARIABLE GLOBALE en plus d'un champ d'objet (cond_source/cond_variable/
cond_variable_chemin — screens/flow/ensure_flow_schema.py), sur la
clause principale ET chaque clause supplémentaire (ET/OU). Évalué côté
CLIENT (templates/play.html, evaluateConditionClause), contre un
nouveau gameData.variables exposé par full_game_payload.py — tenu à
jour par refreshRuntimeData() après toute action qui modifie une
variable, sans changement supplémentaire nécessaire. Le panneau de
condition reste utilisable même sans aucun objet défini dans le jeu
(avant, il disparaissait entièrement).
Vérifié : 153 tests pytest (nouveaux : test_data_binding_clause_list.py,
test_condition_variable.py) + logique JS d'évaluation des conditions
vérifiée isolément avec Node (variable scalaire, objet avec chemin
chaîné, tableau par index, variable introuvable, booléen, rétrocompatibilité
legacy) + rendu des deux pages (éditeur/jeu) vérifié sur le vrai projet
"test" en plus des jeux de test.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
37 lines
1.8 KiB
Python
37 lines
1.8 KiB
Python
import db
|
|
|
|
from .filter_repeater_rows import filter_rows_by_clauses, _field_column
|
|
from ..clause_list_codec import decode_clauses
|
|
|
|
|
|
def _resolve_bound_row_ctx(slug, attrs):
|
|
"""Si cet élément est lié à un objet de données (attr:_data_definition_id —
|
|
réglage "Lier à un objet de données" des widgets Texte/Titre, voir
|
|
DATA_BINDING_CONTROLS), retrouve LA ligne qui correspond aux conditions
|
|
réglées (un nombre quelconque, combinées par ET/OU — attr:
|
|
_data_filtres_json/_data_filtre_combinateur, avec repli sur l'ancien
|
|
format à 2 filtres fixes _data_filtre*/_data_filtre2* pour les éléments
|
|
créés avant l'ajout des clauses illimitées) — même moteur que le
|
|
filtre du Répéteur de données, voir filter_repeater_rows.py — et
|
|
renvoie ses champs sous forme de {nom_du_champ: valeur en texte},
|
|
exploitable par {{champ}} dans le contenu. Permet d'afficher UNE seule
|
|
valeur calculée (ex: l'objectif du niveau en cours) sans avoir besoin de
|
|
poser un Répéteur, qui affiche lui plusieurs lignes. Renvoie None si
|
|
rien n'est lié ou si aucune ligne ne correspond."""
|
|
definition_id = attrs.get("_data_definition_id")
|
|
if not definition_id or not slug:
|
|
return None
|
|
try:
|
|
definition = db.get_definition(slug, int(definition_id))
|
|
except (TypeError, ValueError):
|
|
return None
|
|
if not definition:
|
|
return None
|
|
rows = db.list_rows(slug, definition)
|
|
clauses, combinator = decode_clauses(attrs, "_data_filtres_json", "_data_filtre_combinateur", legacy_prefix="_data_filtre")
|
|
rows = filter_rows_by_clauses(slug, definition, rows, clauses, combinator)
|
|
if not rows:
|
|
return None
|
|
row = rows[0]
|
|
return {f["name"]: str(row.get(_field_column(definition, f["name"]), "") or "") for f in definition["fields"]}
|