Pagination automatique : le contenu qui déborde part sur une nouvelle page
Retour utilisateur du 23/09/2026 : "si il n'y a plus de place sur la page il faut automatiquement créer une autre page [et y] coller le contenu et amener l'utilisateur sur la page" — remplace le comportement précédent (overflow:hidden, contenu clipsé, à gérer manuellement). - Nouvelle capacité serveur : document_engine.move_document_element_to_page (+ route POST /document/<slug>/elements/<id>/move-to-page) déplace un élément (et ses enfants de rangée en cascade) vers une AUTRE page — jusqu'ici move_document_element ne gérait que le réordonnancement DANS la même page. - Client : forgeDocCheckPageOverflow, appelée à la fin de CHAQUE forgeDocRefreshCanvas (point d'entrée unique après toute mutation) : mesure le débordement réel (scrollHeight vs clientHeight), trouve le premier élément top-niveau qui dépasse le bas de la page (getBoundingClientRect, tient compte du zoom), déplace cet élément et tout ce qui le suit vers une page neuve, puis y bascule l'utilisateur. Jamais déclenché sur une page mini-jeu (toujours seule sur sa page, aucun débordement pertinent à corriger). Vérifié par un test jsdom dédié (géométrie simulée via getBoundingClientRect/scrollHeight/clientHeight, jsdom n'ayant pas de vrai moteur de mise en page) : ordre des déplacements, page inchangée si le contenu tient, page mini-jeu jamais scindée. 6 nouveaux tests Python (document_engine + route). 711/711 tests passent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0e8c6efb06
commit
c6e173589f
@@ -57,6 +57,24 @@ affichée).
|
||||
inexistant ne fait rien (retour silencieux après vérification de son
|
||||
existence).
|
||||
|
||||
## `move_document_element_to_page(slug: str, element_id: int, target_page_id: int) -> None`
|
||||
Déplace un élément vers une AUTRE page du même support — utilisé par la
|
||||
pagination automatique (retour utilisateur du 23/09/2026 : quand le
|
||||
contenu déborde d'une page, l'élément en trop est déplacé vers une
|
||||
nouvelle page plutôt que d'y rester tassé). L'élément redevient TOUJOURS
|
||||
top-niveau sur la page cible (`parent_id` remis à `NULL`) — une rangée
|
||||
qui existait sur l'ancienne page n'a aucun sens comme enfant d'une
|
||||
rangée de la page cible. Si l'élément déplacé est lui-même une rangée,
|
||||
ses enfants directs (même `parent_id`) SUIVENT sur la page cible
|
||||
(`page_id` mis à jour en cascade, `parent_id` inchangé) — sans cette
|
||||
cascade ils resteraient orphelins d'une page qu'ils n'occupent plus
|
||||
(`list_document_elements`, filtré par `page_id`, ne les retrouverait
|
||||
plus). Renumérote les anciens frères après le retrait.
|
||||
- **Retour** : aucun.
|
||||
- **Exceptions** : aucune levée explicitement ; un `element_id`
|
||||
inexistant 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
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
from db.supports import connect_support, ensure_document_pages_schema
|
||||
|
||||
|
||||
def move_document_element_to_page(slug: str, element_id: int, target_page_id: int) -> None:
|
||||
"""Déplace un élément vers une AUTRE page du même support — utilisé
|
||||
par la pagination automatique (retour utilisateur du 23/09/2026 :
|
||||
"si il n'y a plus de place sur la page il faut automatiquement créer
|
||||
une autre page [et y déplacer] le contenu", voir
|
||||
static/document/js/document-editor.js, forgeDocCheckPageOverflow).
|
||||
L'élément redevient TOUJOURS top-niveau sur la page cible (parent_id
|
||||
NULL) — une rangée qui existait sur l'ancienne page n'a aucun sens
|
||||
comme enfant d'une rangée de la page cible. Si l'élément déplacé est
|
||||
lui-même une rangée, ses enfants directs (même parent_id) SUIVENT sur
|
||||
la page cible (cascade sur page_id, parent_id inchangé) : sans cette
|
||||
cascade, list_document_elements (filtré par page_id) ne les
|
||||
retrouverait plus, alors qu'ils resteraient en base rattachés à une
|
||||
rangée désormais sur une autre page — état incohérent silencieux."""
|
||||
ensure_document_pages_schema(slug)
|
||||
conn = connect_support(slug)
|
||||
row = conn.execute("SELECT page_id, parent_id FROM _document_elements WHERE id = ?", (element_id,)).fetchone()
|
||||
if not row:
|
||||
conn.close()
|
||||
return
|
||||
old_page_id = row["page_id"]
|
||||
old_parent_id = row["parent_id"]
|
||||
|
||||
old_siblings = [
|
||||
r["id"]
|
||||
for r in conn.execute(
|
||||
"SELECT id FROM _document_elements WHERE page_id = ? AND parent_id IS ? AND id != ? ORDER BY order_index",
|
||||
(old_page_id, old_parent_id, element_id),
|
||||
).fetchall()
|
||||
]
|
||||
for index, sibling_id in enumerate(old_siblings):
|
||||
conn.execute("UPDATE _document_elements SET order_index = ? WHERE id = ?", (index, sibling_id))
|
||||
|
||||
new_top_level_count = conn.execute(
|
||||
"SELECT COUNT(*) AS n FROM _document_elements WHERE page_id = ? AND parent_id IS NULL", (target_page_id,)
|
||||
).fetchone()["n"]
|
||||
conn.execute(
|
||||
"UPDATE _document_elements SET page_id = ?, parent_id = NULL, order_index = ? WHERE id = ?",
|
||||
(target_page_id, new_top_level_count, element_id),
|
||||
)
|
||||
conn.execute("UPDATE _document_elements SET page_id = ? WHERE parent_id = ?", (target_page_id, element_id))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
Reference in New Issue
Block a user