Corrige la régression du correctif overlay : /elements/<id>/geometry plantait (500)
Le correctif précédent (81c31a9) retirait TOUTE position/taille du cadre .canvasElement/.playElement d'une "superposition" pour ne plus piéger son propre z-index:9999 dans un contexte d'empilement local — mais ce même cadre sert aussi, dans l'ÉDITEUR, de prise pour le glisser-déposer/ redimensionnement de ce widget (screen_edit.html). Sans position:absolute + left/top/width/height, ce cadre s'effondre à 0×0 (son contenu réel est en position:fixed, hors flux) : le calcul de geometrie divise alors par une dimension nulle, produit NaN, et JSON.stringify(NaN) envoie littéralement "null" au serveur — qui plantait sur float(None) dans routes/elements/element_geometry.py (500, reproduit par l'utilisateur en posant un template lié à un objet et en essayant de repositionner l'overlay dans l'éditeur). Correctif plus ciblé : le cadre garde position/left/top/width/height comme n'importe quel widget (l'éditeur redevient fonctionnel) — SEUL le z-index est omis pour ce widget précis. position:absolute SANS z-index explicite (donc z-index:auto) ne crée PAS de nouveau contexte d'empilement CSS : le z-index:9999 posé plus profond (render_overlay.py) continue donc de se comparer directement aux autres éléments de l'écran, et gagne toujours — le bug de superposition visuelle (81c31a9) reste corrigé, sans regression sur l'éditeur cette fois. test_confort.py mis à jour (position:absolute attendu, plus d'assertion "position:static") + nouveau test qui appelle directement la route /geometry sur une superposition pour confirmer qu'elle répond 200. 137 tests au vert au total. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5c069ae1fe
commit
7c0f1ed427
@@ -20,25 +20,36 @@ def _element_style(el):
|
||||
Bug corrigé : le widget "superposition" (render_overlay.py) ignore déjà
|
||||
x/y/width/height et pose lui-même position:fixed; inset:0; z-index:9999
|
||||
sur SA PROPRE balise — mais tant que CE cadre-ci gardait quand même
|
||||
"position:absolute; z-index:{z_index}" (le z-index de sa place dans le
|
||||
canevas, souvent petit), il devenait un élément positionné avec z-index
|
||||
explicite, donc un NOUVEAU contexte d'empilement CSS — le z-index:9999
|
||||
posé plus profond ne se comparait alors plus qu'AU SEIN de ce contexte,
|
||||
et perdait face au z-index (plus grand) d'un frère ajouté après lui sur
|
||||
le canevas, qui se retrouvait affiché PAR-DESSUS le dialogue censé tout
|
||||
couvrir. En ne posant ICI aucune position/z-index pour ce widget (sa
|
||||
place dans le flux normal, invisible puisque son contenu est en
|
||||
position:fixed de toute façon), plus aucun contexte d'empilement n'est
|
||||
créé à ce niveau : le z-index:9999 se compare alors directement aux
|
||||
autres éléments de l'écran, et gagne toujours."""
|
||||
if el.get("widget") == "superposition":
|
||||
return "position:static;"
|
||||
return "; ".join([
|
||||
"z-index:{z_index}" (le z-index de sa place dans le canevas, souvent
|
||||
petit), un élément positionné avec un z-index EXPLICITE (même sur ce
|
||||
cadre, pas sur son contenu) devient un NOUVEAU contexte d'empilement
|
||||
CSS — le z-index:9999 posé plus profond ne se comparait alors plus
|
||||
qu'AU SEIN de ce contexte, et perdait face au z-index (plus grand) d'un
|
||||
frère ajouté après lui sur le canevas, qui se retrouvait affiché
|
||||
PAR-DESSUS le dialogue censé tout couvrir.
|
||||
|
||||
Première correction tentée (retirer aussi position/left/top/width/
|
||||
height ici) : régression dans l'ÉDITEUR — ce même cadre (.canvasElement)
|
||||
sert aussi de prise pour glisser-déposer/redimensionner CE widget dans
|
||||
le canevas (voir screen_edit.html), dont le calcul se base sur ses
|
||||
dimensions réelles ; sans position:absolute + left/top/width/height, ce
|
||||
cadre s'effondre à 0×0 (son contenu réel est en position:fixed, donc
|
||||
hors flux), le calcul division par zéro produit NaN, et
|
||||
JSON.stringify(NaN) donne "null" — element_geometry.py plantait alors
|
||||
sur float(None). left/top/width/height restent donc posés comme pour
|
||||
n'importe quel widget (l'éditeur continue de fonctionner normalement) :
|
||||
SEUL le z-index est omis pour ce widget précis. position:absolute SANS
|
||||
z-index explicite (donc z-index:auto) ne crée PAS de nouveau contexte
|
||||
d'empilement — le z-index:9999 posé plus profond se compare alors
|
||||
directement aux autres éléments de l'écran, et gagne toujours."""
|
||||
parts = [
|
||||
"position:absolute",
|
||||
f"left:{el['x']}%", f"top:{el['y']}%",
|
||||
f"width:{el['width']}%", f"height:{el['height']}%",
|
||||
f"z-index:{el['z_index']}",
|
||||
]) + ";"
|
||||
]
|
||||
if el.get("widget") != "superposition":
|
||||
parts.append(f"z-index:{el['z_index']}")
|
||||
return "; ".join(parts) + ";"
|
||||
|
||||
|
||||
def _element_transform_style(el):
|
||||
|
||||
+34
-11
@@ -184,15 +184,19 @@ def test_overlay_widget_renders_fullscreen_fixed_box(client, game):
|
||||
def test_overlay_wrapper_does_not_trap_its_own_z_index(client, game):
|
||||
"""Régression : le cadre .playElement/.canvasElement partagé par TOUS
|
||||
les widgets (voir filters/element_style_filter.py) posait quand même
|
||||
"position:absolute; z-index:<sa place dans le canevas>" sur la
|
||||
superposition, MÊME SI son propre contenu (render_overlay.py) ignore
|
||||
x/y/width/height et pose déjà position:fixed + z-index:9999 lui-même.
|
||||
Un élément positionné avec un z-index explicite crée un NOUVEAU contexte
|
||||
d'empilement CSS : le 9999 posé plus profond ne se comparait alors plus
|
||||
qu'AU SEIN de ce contexte, et perdait face au z-index (plus grand) d'un
|
||||
élément normal ajouté APRÈS l'overlay sur le canevas — qui s'affichait
|
||||
donc PAR-DESSUS le dialogue censé tout couvrir. Le cadre ne doit donc
|
||||
plus poser aucune position/z-index pour ce widget."""
|
||||
"z-index:<sa place dans le canevas>" sur la superposition, MÊME SI son
|
||||
propre contenu (render_overlay.py) ignore x/y/width/height et pose déjà
|
||||
position:fixed + z-index:9999 lui-même. Un élément positionné avec un
|
||||
z-index EXPLICITE crée un NOUVEAU contexte d'empilement CSS : le 9999
|
||||
posé plus profond ne se comparait alors plus qu'AU SEIN de ce contexte,
|
||||
et perdait face au z-index (plus grand) d'un élément normal ajouté
|
||||
APRÈS l'overlay sur le canevas — qui s'affichait donc PAR-DESSUS le
|
||||
dialogue censé tout couvrir. Le cadre garde position/left/top/width/
|
||||
height comme tout widget (l'éditeur en a besoin pour glisser-déposer/
|
||||
redimensionner ce cadre — les retirer a fait planter element_geometry
|
||||
en régression), mais n'écrit plus DU TOUT de z-index pour ce widget :
|
||||
position:absolute avec z-index:auto (omis) ne crée pas de contexte
|
||||
d'empilement, donc le 9999 se compare directement aux autres éléments."""
|
||||
screen_id = _create_screen(client, game)
|
||||
overlay_id = _add_element(client, game, screen_id, "superposition")
|
||||
# Ajouté APRÈS l'overlay -> z_index plus grand que le sien.
|
||||
@@ -204,8 +208,27 @@ def test_overlay_wrapper_does_not_trap_its_own_z_index(client, game):
|
||||
assert idx != -1
|
||||
tag_start = html.rfind("<div", 0, idx)
|
||||
wrapper_tag = html[tag_start:idx + 200]
|
||||
assert "position:static" in wrapper_tag
|
||||
assert "position:absolute" not in wrapper_tag
|
||||
assert "position:absolute" in wrapper_tag
|
||||
assert "z-index" not in wrapper_tag
|
||||
|
||||
|
||||
def test_overlay_geometry_can_still_be_saved_from_the_editor(client, game):
|
||||
"""Régression : la première version du correctif ci-dessus retirait
|
||||
AUSSI position/left/top/width/height du cadre d'une superposition, ce
|
||||
qui effondrait ce cadre à 0×0 dans l'ÉDITEUR (son contenu réel est en
|
||||
position:fixed, hors flux) — le calcul de glisser-déposer/
|
||||
redimensionnement (screen_edit.html) divise alors par une dimension
|
||||
nulle, produit NaN, et JSON.stringify(NaN) envoie "null" : le serveur
|
||||
plantait sur float(None) dans element_geometry.py. Le cadre doit donc
|
||||
continuer à porter une position/taille en % normale pour ce widget."""
|
||||
screen_id = _create_screen(client, game)
|
||||
overlay_id = _add_element(client, game, screen_id, "superposition")
|
||||
resp = client.post(
|
||||
f"/game/{game}/elements/{overlay_id}/geometry",
|
||||
data=json.dumps({"x": 12.5, "y": 20, "width": 55, "height": 45}),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
def test_overlay_starts_hidden_by_default(client, game):
|
||||
|
||||
Reference in New Issue
Block a user