import html as html_lib from ..widgets.widget_meta import widget_meta from .visible_attrs import _visible_attrs from .style_string import _style_string from .attr_string import _attr_string from .apply_ctx import _apply_ctx from .render_children import _render_children from .render_table import _render_table from .render_select import _render_select from .render_fieldset import _render_fieldset from .render_checkbox_or_radio import _render_checkbox_or_radio from .render_repeater import _render_repeater from .render_jauge import _render_jauge from .render_overlay import _render_overlay def render_element_html(el, slug=None, children_map=None, ctx=None, parent_flex_direction=None): """Construit le HTML réel (balise + attributs + style + contenu, y compris les éléments physiquement posés à l'intérieur pour un conteneur/répéteur/groupe de champs) — utilisé par l'éditeur (canevas) et le mode jouable. N'écrit jamais rien sur disque : uniquement du HTML généré à la volée à partir de ce qui est stocké en base. `slug` est nécessaire pour le Répéteur de données (il doit lire les données du jeu au moment de l'affichage). `ctx` porte les valeurs {{champ}} de la ligne en cours quand cet élément est descendant d'un répéteur. `parent_flex_direction` est la disposition interne (voir _parent_flex_direction) du conteneur qui 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")) special = meta.get("special_render") if special == "table": return _render_table(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "select_options": return _render_select(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "fieldset_legend": return _render_fieldset(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "checkbox_label": return _render_checkbox_or_radio(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "repeater": return _render_repeater(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "jauge": return _render_jauge(el, meta, slug, children_map, ctx, parent_flex_direction) if special == "overlay": return _render_overlay(el, meta, slug, children_map, ctx, parent_flex_direction) tag = meta.get("tag") if tag is None: # widget à balise dynamique (ex: "titre" -> h1/h2/h3) niveau = (el.get("attributes") or {}).get("_niveau", "2") tag = f"h{niveau}" attrs = _visible_attrs(el, meta, ctx) style = _style_string(el, parent_flex_direction=parent_flex_direction, widget_key=el.get("widget")) # 3.1 (Confort) — interactions au survol : un texte de remplacement # optionnel, affiché à la place du contenu normal quand le joueur # survole cet élément à la souris (voir bindHoverTexts() dans # templates/play.html). Absent par défaut => aucun changement, donc # aucune régression sur les éléments déjà créés. hover_text = (el.get("attributes") or {}).get("_survol_texte") if hover_text: attrs["data-hover-text"] = _apply_ctx(hover_text, ctx) if meta.get("self_closing"): return f"<{tag} {_attr_string(attrs, style)}>" content = _apply_ctx(el.get("content") or "", ctx) child_html = _render_children(el, slug, children_map, ctx) if tag in ("ul", "ol"): items = [line.strip() for line in content.split("\n") if line.strip()] inner = "".join(f"