Dev #1

Merged
w-vandal merged 62 commits from dev into main 2026-08-26 04:56:44 +00:00
3 changed files with 66 additions and 0 deletions
Showing only changes of commit 94f1414506 - Show all commits
+10
View File
@@ -38,6 +38,16 @@ def _style_string(el, extra_base="", parent_flex_direction=None, widget_key=None
nonlocal has_size_override
if v in (None, ""):
return False
if isinstance(v, (dict, list)):
# Ne devrait jamais arriver (chaque contrôle composite — ex.
# "shadow", voir c_shadow.py — est censé combiner ses sous-
# valeurs en une seule chaîne CSS avant d'être stocké), mais
# sert de filet de sécurité : un dict/une liste écrits tels
# quels ici donneraient une valeur CSS invalide (repr Python)
# qui cassait TOUT le style de l'élément (bug déjà corrigé côté
# écriture — voir default_style_for_widget.py — pour des
# éléments déjà créés avant ce correctif).
return False
if k == "transform" and not is_child:
# Un élément posé directement sur un écran a déjà ce "transform"
# posé sur son cadre .canvasElementInner / .playElementInner
@@ -73,6 +73,16 @@ def default_style_and_attributes(widget_key):
# type de réglage (voir size_override_controls.py) — jamais une
# vraie valeur par défaut à figer à la création.
continue
if ctype == "shadow":
# "default" est un dict composite (voir c_shadow.py), pas une
# valeur CSS directement écrivable — sans cette exclusion, il
# était écrit TEL QUEL (repr Python d'un dict) dans le style de
# TOUT élément fraîchement créé, une valeur CSS invalide qui
# cassait le "box-shadow" de tout élément neuf. Comme pour
# "color" ci-dessus, la valeur par défaut n'est qu'une
# suggestion affichée dans le panneau, pas un réglage neutre à
# figer à la création (le neutre CSS est "pas d'ombre").
continue
if is_native_class_widget and control["key"] in _ZERO_DEFAULT_RESET_KEYS:
continue
target = control.get("target")
+46
View File
@@ -14,6 +14,52 @@ def _create_element(client, slug, widget="conteneur"):
return screen_id, element_id
def test_freshly_created_element_has_no_shadow_baked_in(client, game):
"""Régression : le réglage par défaut du contrôle "shadow" est un dict
composite (voir c_shadow.py), pas une valeur CSS directement écrivable
— sans une exclusion dédiée dans default_style_for_widget.py, il était
écrit TEL QUEL (repr Python d'un dict) dans le style de TOUT élément
fraîchement créé, une valeur CSS invalide qui cassait "box-shadow" (et
donnait l'impression que "les propriétés ne sont pas prises en compte")
sur chaque nouvel élément, quel que soit son widget."""
_screen_id, element_id = _create_element(client, game)
el = screens.get_element(game, element_id)
assert "box-shadow" not in el["style"]
html = client.get(f"/game/{game}/runtime-payload").get_json()
rendered_html = None
for s in html["screens"]:
for e in s["elements"]:
if e["id"] == element_id:
rendered_html = e["rendered_html"]
assert rendered_html is not None
assert "{" not in rendered_html.split("style=")[1].split(">")[0]
def test_already_corrupted_style_does_not_break_the_whole_style_attribute(client, game):
"""Filet de sécurité (voir style_string.py) : un élément déjà touché par
le bug ci-dessus avant son correctif (un dict resté tel quel dans son
style stocké) doit continuer à s'afficher — sans lui, une seule valeur
invalide au milieu de l'attribut style pouvait tout casser."""
import json
import db
_screen_id, element_id = _create_element(client, game, "texte")
el = screens.get_element(game, element_id)
corrupted_style = dict(el["style"])
corrupted_style["box-shadow"] = {"x": 0, "y": 4, "blur": 12, "spread": 0, "color": "#000000", "opacity": 0.4}
conn = db.connect(game)
conn.execute("UPDATE _screen_elements SET style = ? WHERE id = ?", (json.dumps(corrupted_style), element_id))
conn.commit()
conn.close()
html = client.get(f"/game/{game}/screens/{_screen_id}/edit").data.decode()
idx = html.find(f'id="elt-{element_id}"')
style_attr = html[max(0, idx - 400):idx]
assert "{" not in style_attr.split('style="')[-1]
def test_shadow_controls_appear_in_the_properties_panel(client, game):
screen_id, element_id = _create_element(client, game)
html = client.get(f"/game/{game}/screens/{screen_id}/edit?selected={element_id}").data.decode()