fix(js): sync el.style with the style attribute in both directions
CSSStyleDeclaration was backed by an in-memory _props map that was never
bridged to the element's style content attribute. Parsed inline styles were
invisible to el.style.*, setAttribute('style', …) did not update el.style, and
el.style.x = … never reached the attribute or serialization; getComputedStyle
read the same disconnected declaration.
Give the declaration its owner element: lazily pull the style attribute into
_props on read (skipping the reparse when unchanged) and push _props back to the
attribute on every mutation. Owner-less declarations (getComputedStyle fallback,
stylesheet rules) stay purely in-memory, so their behavior is unchanged.
Fixes #488
This commit is contained in:
1 parent
e314b9b0f3
commit
80803cbec8
2 files changed
+123
-18
No files matched your search
@@ -1317,6 +1317,66 @@ mod tests {
|
||||
rt
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn style_attribute_parses_into_style_object() {
|
||||
// Inline styles present in the parsed HTML must be visible via el.style.*
|
||||
let mut rt = setup_runtime(
|
||||
r#"<html><body><div id="d" style="color: red; display: none">hi</div></body></html>"#,
|
||||
);
|
||||
assert_eq!(
|
||||
rt.evaluate("document.getElementById('d').style.color").unwrap(),
|
||||
serde_json::json!("red")
|
||||
);
|
||||
assert_eq!(
|
||||
rt.evaluate("document.getElementById('d').style.display").unwrap(),
|
||||
serde_json::json!("none")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_style_attribute_updates_style_object() {
|
||||
let mut rt = setup_runtime(r#"<html><body><div id="d">hi</div></body></html>"#);
|
||||
let margin = rt
|
||||
.evaluate(
|
||||
"(function(){var e=document.getElementById('d'); e.setAttribute('style','margin: 5px'); return e.style.margin;})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(margin, serde_json::json!("5px"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setting_style_property_updates_the_attribute_and_serialization() {
|
||||
let mut rt = setup_runtime(r#"<html><body><div id="d">hi</div></body></html>"#);
|
||||
let attr = rt
|
||||
.evaluate(
|
||||
"(function(){var e=document.getElementById('d'); e.style.color='blue'; return e.getAttribute('style');})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(attr, serde_json::json!("color: blue;"));
|
||||
let html = rt
|
||||
.evaluate("document.getElementById('d').outerHTML")
|
||||
.unwrap();
|
||||
assert!(
|
||||
html.as_str().unwrap().contains("color: blue"),
|
||||
"outerHTML should carry the style set via el.style: {html}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn style_object_reflects_external_attribute_change() {
|
||||
// A later setAttribute('style', …) must supersede an earlier value read
|
||||
// through el.style (the declaration re-syncs from the attribute).
|
||||
let mut rt = setup_runtime(
|
||||
r#"<html><body><div id="d" style="color: red">hi</div></body></html>"#,
|
||||
);
|
||||
let color = rt
|
||||
.evaluate(
|
||||
"(function(){var e=document.getElementById('d'); e.style.color; e.setAttribute('style','color: green'); return e.style.color;})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(color, serde_json::json!("green"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_document_title() {
|
||||
let mut rt = setup_runtime("<html><head><title>Test</title></head><body></body></html>");
|
||||
|
||||
Reference in new issue
Block a user