mirror of
https://github.com/lexmount/moli.git
synced 2026-10-07 16:01:01 +00:00
fix(events): align lifecycle event initialization
This commit is contained in:
@@ -19,6 +19,10 @@ const BEFORE_UNLOAD_EVENT_RETURN_VALUE_SLOT: &str = "__moliBeforeUnloadEventRetu
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain)]
|
||||
struct PageTransitionEventInitDeclaration {
|
||||
#[webapi(data_property, enumerable)]
|
||||
bubbles: bool,
|
||||
#[webapi(data_property, enumerable)]
|
||||
cancelable: bool,
|
||||
#[webapi(data_property, enumerable)]
|
||||
persisted: bool,
|
||||
}
|
||||
@@ -56,11 +60,13 @@ pub(crate) fn construct_original_event<'s>(
|
||||
let event_ctor =
|
||||
super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "Event").ok()?;
|
||||
let event_type = v8_string(scope, event_type)?;
|
||||
{
|
||||
let event = {
|
||||
let try_catch = std::pin::pin!(v8::TryCatch::new(scope));
|
||||
let scope = try_catch.init();
|
||||
event_ctor.new_instance(&scope, &[event_type.into()])
|
||||
}
|
||||
}?;
|
||||
mark_event_trusted(scope, event);
|
||||
Some(event)
|
||||
}
|
||||
|
||||
fn new_before_unload_event<'s>(
|
||||
@@ -86,7 +92,9 @@ fn new_before_unload_event<'s>(
|
||||
pub(crate) fn construct_original_before_unload_event<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
) -> Option<v8::Local<'s, v8::Object>> {
|
||||
new_before_unload_event(scope, "beforeunload", true)
|
||||
let event = new_before_unload_event(scope, "beforeunload", true)?;
|
||||
mark_event_trusted(scope, event);
|
||||
Some(event)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn new_uninitialized_before_unload_event<'s>(
|
||||
@@ -192,14 +200,16 @@ pub(crate) fn construct_original_page_transition_event<'s>(
|
||||
)
|
||||
.ok()?;
|
||||
let event_type = v8_string(scope, event_type)?;
|
||||
let init = PageTransitionEventInitDeclaration::new(persisted)
|
||||
let init = PageTransitionEventInitDeclaration::new(true, true, persisted)
|
||||
.bind(scope)
|
||||
.expect("PageTransitionEvent init declaration should bind");
|
||||
{
|
||||
let event = {
|
||||
let try_catch = std::pin::pin!(v8::TryCatch::new(scope));
|
||||
let scope = try_catch.init();
|
||||
event_ctor.new_instance(&scope, &[event_type.into(), init.into()])
|
||||
}
|
||||
}?;
|
||||
mark_event_trusted(scope, event);
|
||||
Some(event)
|
||||
}
|
||||
|
||||
pub(crate) fn construct_original_storage_event_utf16<'s>(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::events::{
|
||||
construct_original_before_unload_event, construct_original_event,
|
||||
run_navigate_event_precommit_handlers,
|
||||
construct_original_page_transition_event, run_navigate_event_precommit_handlers,
|
||||
};
|
||||
use super::location_history_storage::{
|
||||
NAVIGATION_ENTRY_EVENT_LISTENERS_SLOT, NAVIGATION_EVENT_LISTENERS_SLOT,
|
||||
@@ -106,13 +106,6 @@ struct HashChangeEventStateDeclaration {
|
||||
new_url: String,
|
||||
}
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain)]
|
||||
struct PageTransitionEventStateDeclaration {
|
||||
#[webapi(data_property)]
|
||||
persisted: bool,
|
||||
}
|
||||
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain)]
|
||||
struct NavigateEventInitDeclaration<'scope> {
|
||||
@@ -645,10 +638,9 @@ pub(crate) fn dispatch_pagehide_for_runtime_owner<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
owner: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
let Some(event) = construct_original_event(scope, "pagehide") else {
|
||||
let Some(event) = construct_original_page_transition_event(scope, "pagehide", false) else {
|
||||
return;
|
||||
};
|
||||
let _ = PageTransitionEventStateDeclaration::new(false).initialize(scope, event);
|
||||
dispatch_unload_lifecycle_event_for_runtime_owner(scope, owner, "pagehide", event);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
content_security_policy::{
|
||||
ContentSecurityPolicyViolationEventFields, send_content_security_policy_reports,
|
||||
},
|
||||
context_bootstrap::{construct_original_event, mark_event_trusted},
|
||||
context_bootstrap::construct_original_event,
|
||||
document_runtime::{
|
||||
DocumentNavigationEmbeddingContext, DocumentPolicyContainer, DomHandle, EventTargetHandle,
|
||||
},
|
||||
@@ -651,7 +651,6 @@ impl JsContextHost {
|
||||
if object_fallback_required {
|
||||
self.enter_object_fallback_state(scope, handle);
|
||||
if let Some(event) = construct_original_event(scope, "error") {
|
||||
mark_event_trusted(scope, event);
|
||||
let host_ptr: *mut JsContextHost = self;
|
||||
let runtime = unsafe { &mut *self.runtime };
|
||||
let _ = runtime.dispatch_public_event_best_effort(
|
||||
|
||||
@@ -2029,9 +2029,16 @@ fn cross_document_unload_lifecycle_orders_pagehide_before_unload_without_timer()
|
||||
r##"
|
||||
(() => {
|
||||
const log = [];
|
||||
addEventListener("beforeunload", () => log.push("beforeunload"));
|
||||
addEventListener("pagehide", event => log.push(`pagehide:${event.persisted}`));
|
||||
addEventListener("unload", () => log.push("unload"));
|
||||
addEventListener("beforeunload", event => log.push(`beforeunload:${event.isTrusted}`));
|
||||
addEventListener("pagehide", event => log.push([
|
||||
"pagehide",
|
||||
event instanceof PageTransitionEvent,
|
||||
event.persisted,
|
||||
event.bubbles,
|
||||
event.cancelable,
|
||||
event.isTrusted
|
||||
].join(":")));
|
||||
addEventListener("unload", event => log.push(`unload:${event.isTrusted}`));
|
||||
navigation.navigate("/next-document");
|
||||
return log.join("|");
|
||||
})()
|
||||
@@ -2039,7 +2046,10 @@ fn cross_document_unload_lifecycle_orders_pagehide_before_unload_without_timer()
|
||||
)
|
||||
.expect("cross-document unload lifecycle should evaluate");
|
||||
|
||||
assert_eq!(lifecycle, "beforeunload|pagehide:false|unload");
|
||||
assert_eq!(
|
||||
lifecycle,
|
||||
"beforeunload:true|pagehide:true:false:true:true:true|unload:true"
|
||||
);
|
||||
assert!(
|
||||
!vm.has_ready_timeout(),
|
||||
"pagehide is part of the unload step and must not create an independent timer task"
|
||||
|
||||
@@ -13780,7 +13780,14 @@ fn window_pageshow_uses_original_page_transition_event() {
|
||||
throw new Error("page replacement should not be invoked");
|
||||
};
|
||||
addEventListener("pageshow", event => {
|
||||
__pageshowShape = `${event.type}:${event.persisted === false}:${'persisted' in event}`;
|
||||
__pageshowShape = [
|
||||
event.type,
|
||||
event.persisted === false,
|
||||
'persisted' in event,
|
||||
event.bubbles,
|
||||
event.cancelable,
|
||||
event.isTrusted
|
||||
].join(':');
|
||||
});
|
||||
return "ready";
|
||||
})()
|
||||
@@ -13793,7 +13800,7 @@ fn window_pageshow_uses_original_page_transition_event() {
|
||||
let shape = vm
|
||||
.eval("globalThis.__pageshowShape")
|
||||
.expect("pageshow shape should evaluate");
|
||||
assert_eq!(shape, "pageshow:true:true");
|
||||
assert_eq!(shape, "pageshow:true:true:true:true:true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -13808,12 +13815,12 @@ fn window_load_uses_original_event_after_global_constructors_are_deleted() {
|
||||
globalThis.__windowLifecycleEvents = [];
|
||||
addEventListener('load', event => {
|
||||
__windowLifecycleEvents.push(
|
||||
`load:${event instanceof OriginalEvent}:${event.target === document}:${event.currentTarget === window}`
|
||||
`load:${event instanceof OriginalEvent}:${event.target === document}:${event.currentTarget === window}:${event.isTrusted}:${event.bubbles}:${event.cancelable}`
|
||||
);
|
||||
});
|
||||
addEventListener('pageshow', event => {
|
||||
__windowLifecycleEvents.push(
|
||||
`pageshow:${event instanceof OriginalPageTransitionEvent}:${event.persisted}`
|
||||
`pageshow:${event instanceof OriginalPageTransitionEvent}:${event.persisted}:${event.isTrusted}:${event.bubbles}:${event.cancelable}`
|
||||
);
|
||||
});
|
||||
delete globalThis.Event;
|
||||
@@ -13829,7 +13836,7 @@ fn window_load_uses_original_event_after_global_constructors_are_deleted() {
|
||||
assert_eq!(
|
||||
vm.eval("__windowLifecycleEvents.join('|')")
|
||||
.expect("window lifecycle results should evaluate"),
|
||||
"load:true:true:true|pageshow:true:false"
|
||||
"load:true:true:true:true:false:false|pageshow:true:false:true:true:true"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user