Nouveau moteur document_engine/ (elements CRUD + rendering + labels), db/supports/ (stockage independant de db/games), routes/document/ (CRUD AJAX + publication), et l'editeur frontend complet (templates/document/, static/document/) avec moteur de layout reel (glisser-deposer -> fusion en rangee ou insertion avant/apres), vrai Undo/Redo par pile de commandes, grille d'accroche pour les formes libres, apercu responsive a largeurs fixes, mode Apercu, et publication persistee. "Mes formations" (templates/index.html) liste desormais les environnements 2D et les supports de formation cote a cote ; l'onboarding et core/auth_guard.py sont generalises pour qu'un compte restreint puisse posseder un projet de chaque type independamment. SKIP=djlint : le hook ne signale que le backlog H021 (styles en ligne) deja documente dans CODE_QUALITY.md sur des fichiers pre-existants non touches ici (base.html, game/play.html, scene_edit.html, game_dashboard_simple.html, clause_row.html) plus une ligne de index.html deja presente avant cette session — aucun nouveau fichier (document_edit.html compris) n'y figure. Tous les autres outils (ruff, mypy --strict, vulture, bandit, import-linter, eslint, stylelint) passent sans erreur ; 617 tests Python + 276 tests JS verts, plus une verification manuelle complete du cycle de vie via le serveur de developpement. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2.9 KiB
document_engine/elements/
CRUD des éléments d'un support de formation (_document_elements, voir
db/supports/create_support.py). Un élément est soit un élément de
contenu/rangée du flux (parent_id = groupe de frères), soit une forme
libre superposée en position absolue (toujours parent_id = NULL).
add_document_element(slug: str, kind: str, parent_id: int | None = None) -> int
Insère un nouvel élément en fin de son groupe de frères (même parent_id).
Pose les attributs de départ via element_default_attributes(kind)
(voir document_engine/labels/element_kind_labels.py).
- Retour : l'
iddu nouvel élément. - Exceptions : aucune levée explicitement ; une connexion invalide (support inexistant) lève l'erreur SQLite sous-jacente.
list_document_elements(slug: str) -> list[dict[str, Any]]
Renvoie tous les éléments du support, à plat, triés par (parent_id, order_index) — les éléments top-niveau (parent_id NULL) groupés en
premier (tri SQLite : NULL avant toute valeur), puis chaque rangée
groupant ses propres enfants. attributes est décodé en dict.
- Retour : liste de dicts (une ligne de table chacun,
attributesdéjà en JSON décodé). - Exceptions : aucune.
get_document_element(slug: str, element_id: int) -> dict[str, Any] | None
Récupère un seul élément par id.
- Retour : le dict de l'élément, ou
Nonesi l'id n'existe pas. - Exceptions : aucune.
update_document_element_attributes(slug: str, element_id: int, attributes: dict[str, Any]) -> None
Remplace intégralement le JSON attributes d'un élément — chaque
formulaire du panneau Propriétés envoie l'état complet de ses champs,
jamais un patch partiel.
- Retour : aucun.
- Exceptions : aucune levée explicitement ; un
element_idinexistant ne modifie silencieusement aucune ligne (UPDATEsans correspondance).
move_document_element(slug: str, element_id: int, new_parent_id: int | None, new_index: int) -> None
Réinsertion réelle appelée par l'algorithme de glisser-déposer du moteur de layout : dépose l'élément dans un groupe de frères (nouvelle rangée, un groupe existant, ou le top-niveau) à une position précise, puis renumérote intégralement le ou les groupes concernés (ancien et nouveau si le parent change, un seul sinon) pour rester correct même en cas de réordonnancement dans le même groupe.
- Retour : aucun.
- Exceptions : aucune levée explicitement ; un
element_idinexistant ne fait rien (retour silencieux après vérification de son existence).
delete_document_element(slug: str, element_id: int) -> None
Supprime un élément. La contrainte FOREIGN KEY ... ON DELETE CASCADE
(voir db/supports/create_support.py) retire automatiquement ses
enfants si l'élément supprimé était une rangée.
- Retour : aucun.
- Exceptions : aucune levée explicitement ; un
element_idinexistant ne modifie silencieusement aucune ligne.