Skip to content

Commit

Permalink
dom: Implement current window event.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdm committed May 13, 2020
1 parent 19f4be3 commit 097a846
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 24 deletions.
20 changes: 12 additions & 8 deletions components/script/dom/event.rs
Expand Up @@ -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>() {
window.set_current_event(Some(event))
} else {
None
};

// Step 2.9 TODO: EventListener passive option not implemented

Expand All @@ -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>() {
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() {
Expand Down
17 changes: 17 additions & 0 deletions components/script/dom/eventtarget.rs
Expand Up @@ -150,6 +150,23 @@ pub enum CompiledEventListener {
}

impl CompiledEventListener {
#[allow(unsafe_code)]
pub fn associated_global(&self) -> DomRoot<GlobalScope> {
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,
Expand Down
4 changes: 4 additions & 0 deletions components/script/dom/webidls/Window.webidl
Expand Up @@ -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 = "/";
Expand Down
30 changes: 30 additions & 0 deletions components/script/dom/window.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Rc<Cell<bool>>>,

/// https://dom.spec.whatwg.org/#window-current-event
current_event: DomRefCell<Option<Dom<Event>>>,
}

impl Window {
Expand Down Expand Up @@ -1334,9 +1338,34 @@ impl WindowMethods for Window {
fn GetSelection(&self) -> Option<DomRoot<Selection>> {
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<DomRoot<Event>> {
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,
Expand Down Expand Up @@ -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) }
Expand Down
13 changes: 0 additions & 13 deletions 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

3 changes: 0 additions & 3 deletions tests/wpt/metadata/dom/idlharness.window.js.ini
Expand Up @@ -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
Expand Down

0 comments on commit 097a846

Please sign in to comment.