diff --git a/screens/animations/ensure_animation_schema.py b/screens/animations/ensure_animation_schema.py
index 10b5bb80..a083b406 100644
--- a/screens/animations/ensure_animation_schema.py
+++ b/screens/animations/ensure_animation_schema.py
@@ -1,29 +1,63 @@
import db
+_CREATE_TABLE = """
+ CREATE TABLE _animation_clips (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
+ element_id INTEGER NOT NULL,
+ kind TEXT NOT NULL DEFAULT 'animate_css',
+ animate_name TEXT,
+ custom_keyframes TEXT,
+ start_time REAL NOT NULL DEFAULT 0,
+ duration REAL NOT NULL DEFAULT 1,
+ delay REAL NOT NULL DEFAULT 0,
+ easing TEXT NOT NULL DEFAULT 'ease',
+ iteration_count TEXT NOT NULL DEFAULT '1',
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
+ );
+ """
+
def ensure_animation_schema(slug):
"""Crée la table des clips d'animation si elle n'existe pas encore —
même principe que ensure_flow_schema.py : un jeu créé avant l'ajout de
cette fonctionnalité n'a pas besoin d'être migré à la main, la première
- ouverture du panneau timeline suffit."""
+ ouverture du panneau timeline suffit.
+
+ element_id désigne, selon game_type, un _screen_elements (éditeur
+ document) OU un _scene_objects (éditeur jeu_2d) — animation-timeline.js
+ est réutilisé TEL QUEL entre les deux éditeurs (voir le plan "Fondations
+ d'une plateforme multi-éditeurs") et ne fait aucune distinction. Pas de
+ contrainte FK vers _screen_elements : une scène jeu_2d n'a pas de ligne
+ correspondante dans cette table, ce qui ferait échouer l'insertion avec
+ PRAGMA foreign_keys=ON (voir db/connection.py). Le nettoyage à la
+ suppression d'un élément/objet est fait manuellement (voir
+ screens/elements/delete_element.py et screens/scenes/delete_scene_object.py),
+ même patron que trigger_element_id/cond_element_a dans
+ ensure_flow_schema.py."""
conn = db.connect(slug)
- conn.executescript(
- """
- CREATE TABLE IF NOT EXISTS _animation_clips (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
- element_id INTEGER NOT NULL REFERENCES _screen_elements(id) ON DELETE CASCADE,
- kind TEXT NOT NULL DEFAULT 'animate_css',
- animate_name TEXT,
- custom_keyframes TEXT,
- start_time REAL NOT NULL DEFAULT 0,
- duration REAL NOT NULL DEFAULT 1,
- delay REAL NOT NULL DEFAULT 0,
- easing TEXT NOT NULL DEFAULT 'ease',
- iteration_count TEXT NOT NULL DEFAULT '1',
- created_at TEXT DEFAULT CURRENT_TIMESTAMP
- );
- """
- )
+ cols = {r["name"]: r for r in conn.execute("PRAGMA table_info(_animation_clips)").fetchall()}
+ if not cols:
+ conn.executescript(_CREATE_TABLE)
+ elif cols["element_id"]["notnull"] and _has_fk_on_element_id(conn):
+ conn.executescript(
+ _CREATE_TABLE.replace("CREATE TABLE _animation_clips", "CREATE TABLE _animation_clips_new")
+ )
+ conn.execute(
+ """INSERT INTO _animation_clips_new
+ (id, screen_id, element_id, kind, animate_name, custom_keyframes,
+ start_time, duration, delay, easing, iteration_count, created_at)
+ SELECT id, screen_id, element_id, kind, animate_name, custom_keyframes,
+ start_time, duration, delay, easing, iteration_count, created_at
+ FROM _animation_clips"""
+ )
+ conn.execute("DROP TABLE _animation_clips")
+ conn.execute("ALTER TABLE _animation_clips_new RENAME TO _animation_clips")
conn.commit()
conn.close()
+
+
+def _has_fk_on_element_id(conn):
+ return any(
+ fk["from"] == "element_id" for fk in conn.execute("PRAGMA foreign_key_list(_animation_clips)").fetchall()
+ )
diff --git a/screens/elements/delete_element.py b/screens/elements/delete_element.py
index 8a769a87..c187d7da 100644
--- a/screens/elements/delete_element.py
+++ b/screens/elements/delete_element.py
@@ -1,11 +1,13 @@
import db
+from ..animations.ensure_animation_schema import ensure_animation_schema
from ..flow.ensure_flow_schema import ensure_flow_schema
from .element_descendant_ids import element_descendant_ids
def delete_element(slug, element_id):
ensure_flow_schema(slug)
+ ensure_animation_schema(slug)
conn = db.connect(slug)
row = conn.execute("SELECT screen_id FROM _screen_elements WHERE id = ?", (element_id,)).fetchone()
if not row:
@@ -39,6 +41,10 @@ def delete_element(slug, element_id):
ids + ids + ids + ids,
)
conn.execute(f"DELETE FROM _actions WHERE target_element_id IN ({placeholders})", ids)
+ # _animation_clips.element_id n'a plus de contrainte FK (voir
+ # ensure_animation_schema.py — réutilisé aussi par les objets de scène
+ # jeu_2d) : nettoyage manuel, même raison que ci-dessus.
+ conn.execute(f"DELETE FROM _animation_clips WHERE element_id IN ({placeholders})", ids)
conn.execute("DELETE FROM _screen_elements WHERE id = ?", (element_id,))
conn.commit()
conn.close()
diff --git a/screens/scenes/delete_scene_object.py b/screens/scenes/delete_scene_object.py
index 14ae886e..5965724e 100644
--- a/screens/scenes/delete_scene_object.py
+++ b/screens/scenes/delete_scene_object.py
@@ -1,6 +1,7 @@
import db
from .ensure_scene_schema import ensure_scene_schema
+from ..animations.ensure_animation_schema import ensure_animation_schema
from ..flow.ensure_flow_schema import ensure_flow_schema
@@ -10,15 +11,19 @@ def delete_scene_object(slug, object_id):
cond_element_b — aucun n'a de contrainte FK, voir
ensure_flow_schema.py) : un nœud qui vise un objet supprimé n'a plus
de sens, même patron que screens/elements/delete_element.py pour le
- DOM."""
+ DOM. Nettoie aussi ses clips d'animation (_animation_clips.element_id,
+ voir ensure_animation_schema.py — réutilisé tel quel par
+ animation-timeline.js pour les deux éditeurs, sans contrainte FK)."""
ensure_scene_schema(slug)
ensure_flow_schema(slug)
+ ensure_animation_schema(slug)
conn = db.connect(slug)
conn.execute(
"""DELETE FROM _flow_nodes WHERE trigger_object_id = ? OR target_object_id = ?
OR cond_element_a = ? OR cond_element_b = ?""",
(object_id, object_id, object_id, object_id),
)
+ conn.execute("DELETE FROM _animation_clips WHERE element_id = ?", (object_id,))
conn.execute("DELETE FROM _scene_objects WHERE id = ?", (object_id,))
conn.commit()
conn.close()
diff --git a/templates/scene_edit.html b/templates/scene_edit.html
index 1a546673..b1265792 100644
--- a/templates/scene_edit.html
+++ b/templates/scene_edit.html
@@ -5,6 +5,17 @@
{% block extra_head %}
+
{% endblock %}
{% block content %}