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:
@@ -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)
|
||||
|
||||
@@ -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"]}
|
||||
Reference in New Issue
Block a user