fix(events): honor PopStateEvent visual transition init

This commit is contained in:
ldm0
2026-09-28 01:46:59 +08:00
parent 8f5b349b2f
commit 4a293256f3
3 changed files with 99 additions and 4 deletions
@@ -156,7 +156,11 @@ fn event_subclass_constructor_callback<'s>(
}
}
EventSubclassKind::InterestEvent => data::initialize_interest_event(scope, event, init),
EventSubclassKind::PopStateEvent => data::initialize_pop_state_event(scope, event, init),
EventSubclassKind::PopStateEvent => {
if !data::initialize_pop_state_event(scope, event, init) {
return;
}
}
EventSubclassKind::PageTransitionEvent => {
data::initialize_page_transition_event(scope, event, init);
}
@@ -197,6 +197,15 @@ struct PopStateEventInitDeclaration<'scope> {
has_ua_visual_transition: bool,
}
#[derive(Default, webidl::WebIdlDictionary)]
#[webidl(prefix = "PopStateEventInit")]
struct PopStateEventInitMembers<'s> {
#[webidl(name = "hasUAVisualTransition", default = false)]
has_ua_visual_transition: bool,
#[webidl(converter = "raw")]
state: Option<v8::Local<'s, v8::Value>>,
}
#[derive(WebApiObject)]
#[webapi(plain, data_properties, enumerable)]
struct PageTransitionEventOwnInitDeclaration {
@@ -508,11 +517,24 @@ pub(in crate::context_bootstrap::events::subclasses) fn initialize_pop_state_eve
scope: &mut v8::PinScope<'s, '_>,
event: v8::Local<'s, v8::Object>,
init: Option<v8::Local<'s, v8::Object>>,
) {
let state = init_value_property(scope, init, "state").unwrap_or_else(|| v8::null(scope).into());
PopStateEventInitDeclaration::new(state, false)
) -> bool {
let parsed = match init {
Some(init) => {
match webidl::parse_dictionary_object::<PopStateEventInitMembers>(scope, init) {
Ok(parsed) => parsed,
Err(error) => {
webidl::throw_error(scope, &error);
return false;
}
}
}
None => PopStateEventInitMembers::default(),
};
let state = parsed.state.unwrap_or_else(|| v8::null(scope).into());
PopStateEventInitDeclaration::new(state, parsed.has_ua_visual_transition)
.initialize(scope, event)
.expect("PopStateEvent init declaration should initialize");
true
}
pub(in crate::context_bootstrap::events::subclasses) fn initialize_page_transition_event<'s>(
@@ -1722,3 +1722,72 @@ fn window_error_handler_only_boolean_true_cancels() {
"[[false,true],[true,false],[true,false],[true,false]]"
);
}
#[test]
fn pop_state_event_constructor_converts_visual_transition_and_state_members() {
let mut vm = new_storage_test_vm("https://pop-state-event-constructor.test/");
let result = vm
.eval(
r#"
(() => {
const reads = [];
const state = { marker: true };
const initialized = new PopStateEvent("popstate", {
get state() {
reads.push("state");
return state;
},
get hasUAVisualTransition() {
reads.push("hasUAVisualTransition");
return 1;
}
});
let dispatchedState = null;
let dispatchedTransition = false;
addEventListener("popstate", event => {
dispatchedState = event.state;
dispatchedTransition = event.hasUAVisualTransition;
}, { once: true });
dispatchEvent(initialized);
let getterError = "none";
try {
new PopStateEvent("popstate", {
get hasUAVisualTransition() {
throw new RangeError("sentinel");
}
});
} catch (error) {
getterError = `${error.name}:${error.message}`;
}
return JSON.stringify({
defaults: [
new PopStateEvent("popstate").state,
new PopStateEvent("popstate").hasUAVisualTransition
],
initialized: [
initialized.state === state,
initialized.hasUAVisualTransition,
reads.join(",")
],
explicitFalse: new PopStateEvent("popstate", {
hasUAVisualTransition: 0
}).hasUAVisualTransition,
dispatched: [
dispatchedState === state,
dispatchedTransition
],
getterError
});
})()
"#,
)
.expect("PopStateEvent constructor dictionary probe should evaluate");
assert_eq!(
result,
r#"{"defaults":[null,false],"initialized":[true,true,"hasUAVisualTransition,state"],"explicitFalse":false,"dispatched":[true,true],"getterError":"RangeError:sentinel"}"#
);
}