- The "icone" widget no longer appears as a generic tile in "Ajouter un élément sur l'écran" / "Ajouter DANS ce conteneur" — the icon gallery (now living under "Ajouter un élément sur l'écran" in the left panel instead of the right one) is the only way to add one, always pre-set to the icon you picked. - The element tree now supports dragging an element onto a container row to move it inside (last child), from anywhere in the tree — not just reordering within the same parent. Hovering a container row splits it into before/after/inside zones (thirds) when dragging a sibling, or "inside only" when dragging from elsewhere in the tree. New move_element_to_container() rejects non-container targets and cycles (dropping a container into itself or one of its own descendants) silently, mirroring reorder_element's existing safety pattern. Verified end to end: gallery renders in the left panel with no icone tile in the widget grids, and the move endpoint correctly reparents, rejects a cycle, and rejects a non-container target. Full suite green (89).
63 lines
2.4 KiB
Python
63 lines
2.4 KiB
Python
import db
|
|
|
|
from ..widgets.container_widgets import CONTAINER_WIDGETS
|
|
|
|
|
|
def move_element_to_container(slug, element_id, new_parent_id):
|
|
"""Déplace element_id pour qu'il devienne un enfant de new_parent_id
|
|
(glisser-déposer dans l'arborescence, voir screen_edit.html) — posé en
|
|
DERNIER enfant, l'ordre précis à l'intérieur se règle ensuite comme
|
|
d'habitude par glisser-déposer entre frères et sœurs (voir
|
|
reorder_element.py). Refuse silencieusement (ne touche à rien) si :
|
|
new_parent_id n'est pas un widget conteneur, si c'est element_id
|
|
lui-même, ou si c'est un de ses propres descendants (ça créerait un
|
|
cycle — un conteneur ne peut pas finir posé à l'intérieur de lui-même)."""
|
|
conn = db.connect(slug)
|
|
rows = conn.execute(
|
|
"SELECT id, screen_id, parent_id, widget, z_index FROM _screen_elements WHERE id IN (?, ?)",
|
|
(element_id, new_parent_id),
|
|
).fetchall()
|
|
by_id = {r["id"]: r for r in rows}
|
|
el = by_id.get(element_id)
|
|
target = by_id.get(new_parent_id)
|
|
if not el or not target or el["screen_id"] != target["screen_id"]:
|
|
conn.close()
|
|
return
|
|
if target["widget"] not in CONTAINER_WIDGETS:
|
|
conn.close()
|
|
return
|
|
if new_parent_id == element_id:
|
|
conn.close()
|
|
return
|
|
|
|
# Cycle : new_parent_id ne doit pas être element_id, ni un descendant de
|
|
# element_id (direct ou indirect) — sinon element_id finirait posé à
|
|
# l'intérieur de sa propre arborescence.
|
|
children_of = {}
|
|
for r in conn.execute(
|
|
"SELECT id, parent_id FROM _screen_elements WHERE screen_id = ?", (el["screen_id"],)
|
|
).fetchall():
|
|
if r["parent_id"]:
|
|
children_of.setdefault(r["parent_id"], []).append(r["id"])
|
|
stack = list(children_of.get(element_id, []))
|
|
descendants = set()
|
|
while stack:
|
|
node = stack.pop()
|
|
if node in descendants:
|
|
continue
|
|
descendants.add(node)
|
|
stack.extend(children_of.get(node, []))
|
|
if new_parent_id in descendants:
|
|
conn.close()
|
|
return
|
|
|
|
max_z = conn.execute(
|
|
"SELECT MAX(z_index) AS m FROM _screen_elements WHERE screen_id = ?", (el["screen_id"],)
|
|
).fetchone()["m"]
|
|
conn.execute(
|
|
"UPDATE _screen_elements SET parent_id = ?, z_index = ? WHERE id = ?",
|
|
(new_parent_id, (max_z or 0) + 1, element_id),
|
|
)
|
|
conn.commit()
|
|
conn.close()
|