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"]}