Let Texte/Titre elements bind directly to a single row of another object

Adds a "Donnée liée" settings group to Texte/Titre: pick an object, optionally match it to the current game state via 1-2 filter conditions (same engine as the data-repeater's filter, including {{Objet.champ}} cross-references), and use {{champ}} in the text content to show a field from that one matching row. Unlike the data repeater — built for showing a list of rows — this covers displaying a single computed value (e.g. the objective of the level matching the game's current parcours/level) without wrapping it in a repeater.
This commit is contained in:
william
2026-08-24 11:02:54 +02:00
parent f58fb2bc3d
commit 0e5db97180
5 changed files with 74 additions and 3 deletions
+4
View File
@@ -14,6 +14,7 @@ from .render_repeater import _render_repeater
from .render_jauge import _render_jauge
from .render_overlay import _render_overlay
from .render_onglets import _render_onglets
from .resolve_bound_row import _resolve_bound_row_ctx
def render_element_html(el, slug=None, children_map=None, ctx=None, parent_flex_direction=None):
@@ -29,6 +30,9 @@ def render_element_html(el, slug=None, children_map=None, ctx=None, parent_flex_
pose physiquement cet élément, s'il y en a un — elle influence la largeur
par défaut de cet élément (voir _style_string)."""
meta = widget_meta(el.get("widget"))
bound_ctx = _resolve_bound_row_ctx(slug, el.get("attributes") or {})
if bound_ctx:
ctx = {**(ctx or {}), **bound_ctx}
special = meta.get("special_render")
if special == "table":
return _render_table(el, meta, slug, children_map, ctx, parent_flex_direction)
+38
View File
@@ -0,0 +1,38 @@
import db
from .filter_repeater_rows import filter_repeater_rows
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 1 ou 2
filtres réglés (_data_filtre*/_data_filtre2*) — 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)
rows = filter_repeater_rows(slug, definition, rows, {
"_filtre_champ": attrs.get("_data_filtre_champ"),
"_filtre_operateur": attrs.get("_data_filtre_operateur"),
"_filtre_valeur": attrs.get("_data_filtre_valeur"),
"_filtre2_champ": attrs.get("_data_filtre2_champ"),
"_filtre2_operateur": attrs.get("_data_filtre2_operateur"),
"_filtre2_valeur": attrs.get("_data_filtre2_valeur"),
})
if not rows:
return None
row = rows[0]
return {f["name"]: str(row.get(db.slugify(f["name"]).replace("-", "_"), "") or "") for f in definition["fields"]}