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()