Problème remonté : un déclencheur "Au clic" posé sur un Répéteur exécute
le MÊME graphe pour n'importe quelle ligne cliquée - or une Condition
("Si is_opened est égal à Non") ou une action "Modifier une donnée" ne
pouvaient viser qu'une ligne FIXE, choisie à la création du nœud dans
l'éditeur. Impossible donc de dire "modifie le champ DE LA LIGNE QUE JE
VIENS DE CLIQUER", puisque cette ligne n'est justement jamais connue à
l'avance.
Nouvelle valeur sentinelle CLICKED_ROW_ID (-1, screens/flow/constants.py,
ne collisionne jamais avec un vrai id de ligne) proposée en tête de TOUTE
liste déroulante "Ligne concernée" (clause principale et clauses
supplémentaires d'un nœud Condition, cible d'une action "Modifier une
donnée") : "🖱️ Ligne cliquée (Répéteur)".
Résolution au moment de l'exécution, pas à la création du nœud :
- Condition (évaluée côté client) : readFieldValue() (play.html) résout
-1 en window.lastClickedRowId, déjà capturé par bindClicks() au clic sur
une ligne de Répéteur (déjà utilisé par "Ouvrir la ligne cliquée").
- Action "Modifier une donnée" (exécutée côté serveur) : le client envoie
clicked_row_id dans le corps de la requête POST ; flow_node_run_data.py
ne s'en sert que si le nœud vise justement CLICKED_ROW_ID, sinon la
ligne fixe stockée sur le nœud reste utilisée normalement.
Ajoute tests/test_flow_clicked_row.py (ligne cliquée seule modifiée,
absence de clic = no-op plutôt que plantage, non-régression d'une cible
fixe, présence de l'option dans l'éditeur).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
122 lines
6.2 KiB
Python
122 lines
6.2 KiB
Python
"""
|
|
screens.py — écrans de jeu : éléments posés en glisser-déposer sur un
|
|
écran, sans jamais toucher à un fichier HTML/CSS, enchaînement des écrans,
|
|
et actions déclenchées par clic ou soumission de formulaire.
|
|
|
|
Version 3 — inspirée d'Elementor / Bricks Builder : un catalogue fermé de
|
|
WIDGETS (Texte, Titre, Image, Bouton, Case à cocher, Répéteur de
|
|
données...), chacun avec ses propres réglages ("controls") : un réglage =
|
|
un champ, une case à cocher, un bouton radio ou un curseur — jamais de nom
|
|
de balise ni de nom de propriété CSS à taper. En coulisses, chaque widget
|
|
correspond à une vraie balise HTML avec de vrais attributs et un vrai
|
|
style CSS ; l'utilisateur ne les manipule jamais directement.
|
|
|
|
Tout est stocké dans la même base SQLite que le reste du jeu
|
|
(projects/<slug>/game.db) :
|
|
- _screens : un écran du jeu (accueil, formulaire, scène...)
|
|
- _element_types : le "catalogue" des éléments de jeu réutilisables
|
|
(Personnage, Outil, IA...) que l'utilisateur crée
|
|
- _screen_elements : chaque élément posé sur un écran (widget, position
|
|
et taille en POURCENTAGE de l'écran, contenu,
|
|
attributs et style — dérivés des réglages du
|
|
widget, jamais saisis en texte libre)
|
|
- _actions : ce qui se passe au clic / à la soumission d'un
|
|
élément (écran suivant, écran précédent, aller à
|
|
un écran précis, ne rien faire)
|
|
|
|
Un élément peut aussi être un "Répéteur de données" : au lieu d'un contenu
|
|
fixe, il est relié à un objet défini dans ce jeu (voir db.py) et affiche
|
|
automatiquement une ligne par donnée existante — par exemple, tous les
|
|
niveaux d'un parcours — à partir d'un modèle de texte avec des
|
|
{{nom_de_champ}}.
|
|
|
|
Ce fichier est désormais un package (voir les sous-dossiers) organisé
|
|
selon "un fichier = une fonction, un dossier = une responsabilité" ; ce
|
|
module se contente de ré-exporter l'intégralité de l'API publique
|
|
utilisée par app.py et les templates, afin que `import screens` continue
|
|
de fonctionner à l'identique.
|
|
"""
|
|
|
|
from .widgets.registry import WIDGETS
|
|
from .widgets.container_widgets import CONTAINER_WIDGETS
|
|
from .widgets.layout_capable_widgets import LAYOUT_CAPABLE_WIDGETS
|
|
from .widgets.font_options import GOOGLE_FONTS_LINK
|
|
from .widgets.fontawesome_icons import FONTAWESOME_ICONS
|
|
from .widgets.widget_meta import widget_meta
|
|
from .widgets.controls_with_values import controls_with_values
|
|
from .widgets.data_definition_options import data_definition_options
|
|
|
|
from .labels.trigger_labels import TRIGGER_LABELS
|
|
from .labels.action_type_labels import ACTION_TYPE_LABELS
|
|
from .labels.element_action_properties import (
|
|
ELEMENT_ACTION_PROPERTIES, ELEMENT_ACTION_PROPERTY_LABELS,
|
|
ELEMENT_SURBRILLANCE_VALUES, ELEMENT_SURBRILLANCE_LABELS,
|
|
ELEMENT_DESACTIVE_VALUES, ELEMENT_DESACTIVE_LABELS,
|
|
)
|
|
from .labels.element_visibility import ELEMENT_VISIBILITY_VALUES, ELEMENT_VISIBILITY_LABELS
|
|
from .labels.data_operations import DATA_OPERATIONS, DATA_OPERATION_LABELS
|
|
|
|
from .flow.constants import TRIGGER_EVENTS, CONDITION_OPERATORS, CONDITION_OPERATOR_LABELS, CLICKED_ROW_ID
|
|
|
|
from .rendering.render_element_html import render_element_html
|
|
from .rendering.trigger_for import _trigger_for
|
|
|
|
from .screens_repo.ensure_schema import ensure_schema
|
|
from .screens_repo.list_screens import list_screens
|
|
from .screens_repo.get_screen import get_screen
|
|
from .screens_repo.create_screen import create_screen
|
|
from .screens_repo.rename_screen import rename_screen
|
|
from .screens_repo.delete_screen import delete_screen
|
|
from .screens_repo.move_screen import move_screen
|
|
from .screens_repo.screens_referencing import screens_referencing
|
|
from .screens_repo.set_screen_aspect import set_screen_aspect
|
|
|
|
from .elements.list_elements import list_elements
|
|
from .elements.get_element import get_element
|
|
from .elements.add_element import add_element
|
|
from .elements.add_tab import add_tab
|
|
from .elements.update_element_geometry import update_element_geometry
|
|
from .elements.reorder_element import reorder_element
|
|
from .elements.move_element_to_container import move_element_to_container
|
|
from .elements.save_element_controls import save_element_controls
|
|
from .elements.delete_element import delete_element
|
|
from .elements.flow_nodes_referencing_element import flow_nodes_referencing_element
|
|
from .elements.duplicate_element import duplicate_element
|
|
from .elements.rename_element import rename_element
|
|
from .elements.element_label import element_label
|
|
|
|
from .element_types.list_element_types import list_element_types
|
|
from .element_types.get_element_type_by_template_screen import get_element_type_by_template_screen
|
|
from .element_types.create_element_type import create_element_type
|
|
from .element_types.update_element_type import update_element_type
|
|
from .element_types.element_type_usage_count import element_type_usage_count
|
|
from .element_types.delete_element_type import delete_element_type
|
|
|
|
from .legacy_actions.list_actions import list_actions
|
|
from .legacy_actions.add_action import add_action
|
|
from .legacy_actions.get_action import get_action
|
|
from .legacy_actions.delete_action import delete_action
|
|
|
|
from .flow.ensure_flow_schema import ensure_flow_schema
|
|
from .flow.list_flow_nodes import list_flow_nodes
|
|
from .flow.list_flow_edges import list_flow_edges
|
|
from .flow.get_flow_node import get_flow_node
|
|
from .flow.add_flow_node import add_flow_node
|
|
from .flow.move_flow_node import move_flow_node
|
|
from .flow.delete_flow_node import delete_flow_node
|
|
from .flow.add_flow_edge import add_flow_edge
|
|
from .flow.delete_flow_edge import delete_flow_edge
|
|
|
|
from .data_actions.apply_data_action import apply_data_action
|
|
from .data_actions.apply_variable_action import apply_variable_action
|
|
|
|
from .animations.ensure_animation_schema import ensure_animation_schema
|
|
from .animations.list_animation_clips import list_animation_clips
|
|
from .animations.get_animation_clip import get_animation_clip
|
|
from .animations.add_animation_clip import add_animation_clip
|
|
from .animations.update_animation_clip import update_animation_clip
|
|
from .animations.delete_animation_clip import delete_animation_clip
|
|
from .animations.animate_css_catalog import ANIMATE_CSS_CATALOG, ANIMATE_CSS_LABELS
|
|
|
|
from .payload.full_game_payload import full_game_payload
|