diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 86c5b1caaa1..4577835d24e 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -3669,6 +3669,11 @@ impl ProfilerMetadataFactory for Document { } impl DocumentMethods for Document { + // https://w3c.github.io/editing/ActiveDocuments/execCommand.html#querycommandsupported() + fn QueryCommandSupported(&self, _command: DOMString) -> bool { + false + } + // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { self.stylesheet_list.or_init(|| { diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs index 3a0e7490fc9..8093bd852a9 100644 --- a/components/script/dom/event.rs +++ b/components/script/dom/event.rs @@ -690,12 +690,15 @@ fn inner_invoke( object.remove_listener_if_once(&event.type_(), &event_listener); } - // Step 2.6-2.8 - // FIXME(#25478): we need to get the global that the event - // listener is going to be called on, then if it's a Window - // set its .event to the event, remembering the previous - // value of its .event. This allows events to just use - // the word "event" instead of taking the event as an argument. + // Step 2.6 + let global = listener.associated_global(); + + // Step 2.7-2.8 + let current_event = if let Some(window) = global.downcast::() { + window.set_current_event(Some(event)) + } else { + None + }; // Step 2.9 TODO: EventListener passive option not implemented @@ -712,8 +715,9 @@ fn inner_invoke( // Step 2.11 TODO: passive not implemented // Step 2.12 - // TODO This is where we put back the .event we - // had before step 2.6. + if let Some(window) = global.downcast::() { + window.set_current_event(current_event.as_ref().map(|e| &**e)); + } // Step 2.13: short-circuit instead of going to next listener if event.stop_immediate.get() { diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index b65fcc6baf1..0acc09ce599 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -150,6 +150,23 @@ pub enum CompiledEventListener { } impl CompiledEventListener { + #[allow(unsafe_code)] + pub fn associated_global(&self) -> DomRoot { + let obj = match self { + CompiledEventListener::Listener(listener) => listener.callback(), + CompiledEventListener::Handler(CommonEventHandler::EventHandler(handler)) => { + handler.callback() + }, + CompiledEventListener::Handler(CommonEventHandler::ErrorEventHandler(handler)) => { + handler.callback() + }, + CompiledEventListener::Handler(CommonEventHandler::BeforeUnloadEventHandler( + handler, + )) => handler.callback(), + }; + unsafe { GlobalScope::from_object(obj) } + } + // https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm pub fn call_or_handle_event( &self, diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 8ca4bbe50a1..d2429e51489 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -142,7 +142,7 @@ partial /*sealed*/ interface Document { // boolean queryCommandEnabled(DOMString commandId); // boolean queryCommandIndeterm(DOMString commandId); // boolean queryCommandState(DOMString commandId); - // boolean queryCommandSupported(DOMString commandId); + boolean queryCommandSupported(DOMString commandId); // DOMString queryCommandValue(DOMString commandId); // special event handler IDL attributes that only apply to Document objects diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index f0b5b47d7af..71f03a2e1f4 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -180,6 +180,10 @@ partial interface Window { Selection? getSelection(); }; +// https://dom.spec.whatwg.org/#interface-window-extensions +partial interface Window { + [Replaceable] readonly attribute any event; // historical +}; dictionary WindowPostMessageOptions : PostMessageOptions { USVString targetOrigin = "/"; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index cbf19039605..ff189f2dc9b 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -83,6 +83,7 @@ use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect}; use euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; +use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsapi::JSAutoRealm; use js::jsapi::JSObject; @@ -340,6 +341,9 @@ pub struct Window { /// those values will cause the marker to be set to false. #[ignore_malloc_size_of = "Rc is hard"] layout_marker: DomRefCell>>, + + /// https://dom.spec.whatwg.org/#window-current-event + current_event: DomRefCell>>, } impl Window { @@ -1334,9 +1338,34 @@ impl WindowMethods for Window { fn GetSelection(&self) -> Option> { self.document.get().and_then(|d| d.GetSelection()) } + + // https://dom.spec.whatwg.org/#dom-window-event + #[allow(unsafe_code)] + fn Event(&self, cx: JSContext) -> JSVal { + rooted!(in(*cx) let mut rval = UndefinedValue()); + if let Some(ref event) = *self.current_event.borrow() { + unsafe { + event + .reflector() + .get_jsobject() + .to_jsval(*cx, rval.handle_mut()); + } + } + rval.get() + } } impl Window { + pub(crate) fn set_current_event(&self, event: Option<&Event>) -> Option> { + let current = self + .current_event + .borrow() + .as_ref() + .map(|e| DomRoot::from_ref(&**e)); + *self.current_event.borrow_mut() = event.map(|e| Dom::from_ref(e)); + current + } + /// https://html.spec.whatwg.org/multipage/#window-post-message-steps fn post_message_impl( &self, @@ -2375,6 +2404,7 @@ impl Window { event_loop_waker, visible: Cell::new(true), layout_marker: DomRefCell::new(Rc::new(Cell::new(true))), + current_event: DomRefCell::new(None), }); unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) } diff --git a/tests/wpt/metadata/dom/events/event-global.html.ini b/tests/wpt/metadata/dom/events/event-global.html.ini index 96ad1069096..706c2352cfb 100644 --- a/tests/wpt/metadata/dom/events/event-global.html.ini +++ b/tests/wpt/metadata/dom/events/event-global.html.ini @@ -1,19 +1,6 @@ [event-global.html] - [event exists on window, which is initially set to undefined] - expected: FAIL - - [window.event is only defined during dispatch] - expected: FAIL - [window.event is undefined if the target is in a shadow tree (event dispatched outside shadow tree)] expected: FAIL [window.event is undefined if the target is in a shadow tree (event dispatched inside shadow tree)] expected: FAIL - - [window.event is set to the current event during dispatch] - expected: FAIL - - [window.event is set to the current event, which is the event passed to dispatch] - expected: FAIL - diff --git a/tests/wpt/metadata/dom/idlharness.window.js.ini b/tests/wpt/metadata/dom/idlharness.window.js.ini index cd0dd3b9326..f340ff4f56c 100644 --- a/tests/wpt/metadata/dom/idlharness.window.js.ini +++ b/tests/wpt/metadata/dom/idlharness.window.js.ini @@ -152,9 +152,6 @@ [AbortSignal interface object length] expected: FAIL - [Window interface: attribute event] - expected: FAIL - [AbortController interface: new AbortController() must inherit property "abort()" with the proper type] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/idlharness.https.html.ini b/tests/wpt/metadata/html/dom/idlharness.https.html.ini index 3fa4a76ee55..ead25462f30 100644 --- a/tests/wpt/metadata/html/dom/idlharness.https.html.ini +++ b/tests/wpt/metadata/html/dom/idlharness.https.html.ini @@ -1417,9 +1417,6 @@ [Document interface: iframe.contentDocument must inherit property "dir" with the proper type] expected: FAIL - [Document interface: new Document() must inherit property "queryCommandSupported(DOMString)" with the proper type] - expected: FAIL - [Window interface: attribute onsecuritypolicyviolation] expected: FAIL @@ -1441,9 +1438,6 @@ [Window interface: attribute menubar] expected: FAIL - [Document interface: calling queryCommandSupported(DOMString) on documentWithHandlers with too few arguments must throw TypeError] - expected: FAIL - [Document interface: attribute designMode] expected: FAIL @@ -1480,15 +1474,9 @@ [Document interface: calling execCommand(DOMString, boolean, DOMString) on new Document() with too few arguments must throw TypeError] expected: FAIL - [Document interface: calling queryCommandSupported(DOMString) on new Document() with too few arguments must throw TypeError] - expected: FAIL - [Window interface: operation focus()] expected: FAIL - [Document interface: documentWithHandlers must inherit property "queryCommandSupported(DOMString)" with the proper type] - expected: FAIL - [Window interface: attribute scrollbars] expected: FAIL @@ -1516,9 +1504,6 @@ [Document interface: iframe.contentDocument must inherit property "queryCommandValue(DOMString)" with the proper type] expected: FAIL - [Document interface: operation queryCommandSupported(DOMString)] - expected: FAIL - [Document interface: iframe.contentDocument must inherit property "all" with the proper type] expected: FAIL @@ -1588,9 +1573,6 @@ [Window interface: window must inherit property "blur()" with the proper type] expected: FAIL - [Document interface: iframe.contentDocument must inherit property "queryCommandSupported(DOMString)" with the proper type] - expected: FAIL - [Document interface: calling execCommand(DOMString, boolean, DOMString) on iframe.contentDocument with too few arguments must throw TypeError] expected: FAIL @@ -1621,9 +1603,6 @@ [Document interface: iframe.contentDocument must inherit property "queryCommandEnabled(DOMString)" with the proper type] expected: FAIL - [Document interface: calling queryCommandSupported(DOMString) on iframe.contentDocument with too few arguments must throw TypeError] - expected: FAIL - [Window interface: operation blur()] expected: FAIL