diff --git a/js/event_target.ts b/js/event_target.ts index 96ce8e2a89..bfa9eb6ac7 100644 --- a/js/event_target.ts +++ b/js/event_target.ts @@ -10,6 +10,7 @@ import { isSlotable, retarget } from "./dom_util.ts"; +import { window } from "./window.ts"; // https://dom.spec.whatwg.org/#get-the-parent // Note: Nodes, shadow roots, and documents override this algorithm so we set it to null. @@ -117,6 +118,8 @@ export class EventTarget implements domTypes.EventTarget { callback: (event: domTypes.Event) => void | null, options?: domTypes.AddEventListenerOptions | boolean ): void { + const this_ = this || window; + requiredArguments("EventTarget.addEventListener", arguments.length, 2); const normalizedOptions: domTypes.AddEventListenerOptions = eventTargetHelpers.normalizeAddEventHandlerOptions( options @@ -126,7 +129,7 @@ export class EventTarget implements domTypes.EventTarget { return; } - const listeners = this[domTypes.eventTargetListeners]; + const listeners = this_[domTypes.eventTargetListeners]; if (!hasOwnProperty(listeners, type)) { listeners[type] = []; @@ -153,8 +156,10 @@ export class EventTarget implements domTypes.EventTarget { callback: (event: domTypes.Event) => void | null, options?: domTypes.EventListenerOptions | boolean ): void { + const this_ = this || window; + requiredArguments("EventTarget.removeEventListener", arguments.length, 2); - const listeners = this[domTypes.eventTargetListeners]; + const listeners = this_[domTypes.eventTargetListeners]; if (hasOwnProperty(listeners, type) && callback !== null) { listeners[type] = listeners[type].filter( (listener): boolean => listener.callback !== callback @@ -191,8 +196,10 @@ export class EventTarget implements domTypes.EventTarget { } public dispatchEvent(event: domTypes.Event): boolean { + const this_ = this || window; + requiredArguments("EventTarget.dispatchEvent", arguments.length, 1); - const listeners = this[domTypes.eventTargetListeners]; + const listeners = this_[domTypes.eventTargetListeners]; if (!hasOwnProperty(listeners, event.type)) { return true; } @@ -211,7 +218,7 @@ export class EventTarget implements domTypes.EventTarget { ); } - return eventTargetHelpers.dispatch(this, event); + return eventTargetHelpers.dispatch(this_, event); } get [Symbol.toStringTag](): string { diff --git a/js/event_target_test.ts b/js/event_target_test.ts index 34c486b9f3..9d7e7974c4 100644 --- a/js/event_target_test.ts +++ b/js/event_target_test.ts @@ -88,7 +88,7 @@ test(function constructedEventTargetUseObjectPrototype(): void { assertEquals(callCount, 2); }); -test(function toStringShouldBeWebCompatibility(): void { +test(function toStringShouldBeWebCompatible(): void { const target = new EventTarget(); assertEquals(target.toString(), "[object EventTarget]"); }); @@ -111,3 +111,32 @@ test(function dispatchEventShouldNotThrowError(): void { assertEquals(hasThrown, false); }); + +test(function eventTargetThisShouldDefaultToWindow(): void { + const { + addEventListener, + dispatchEvent, + removeEventListener + } = EventTarget.prototype; + let n = 1; + const event = new Event("hello"); + const listener = (): void => { + n = 2; + }; + + addEventListener("hello", listener); + window.dispatchEvent(event); + assertEquals(n, 2); + n = 1; + removeEventListener("hello", listener); + window.dispatchEvent(event); + assertEquals(n, 1); + + window.addEventListener("hello", listener); + dispatchEvent(event); + assertEquals(n, 2); + n = 1; + window.removeEventListener("hello", listener); + dispatchEvent(event); + assertEquals(n, 1); +});