mirror of
https://github.com/denoland/deno.git
synced 2024-11-29 16:30:56 -05:00
Support async function and EventListenerObject as listeners (#4240)
This commit is contained in:
parent
54a1688868
commit
c850b258b4
5 changed files with 140 additions and 53 deletions
|
@ -76,20 +76,44 @@ export const eventTargetListeners: unique symbol = Symbol();
|
||||||
export const eventTargetMode: unique symbol = Symbol();
|
export const eventTargetMode: unique symbol = Symbol();
|
||||||
export const eventTargetNodeType: unique symbol = Symbol();
|
export const eventTargetNodeType: unique symbol = Symbol();
|
||||||
|
|
||||||
|
export interface EventListener {
|
||||||
|
// Different from lib.dom.d.ts. Added Promise<void>
|
||||||
|
(evt: Event): void | Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventListenerObject {
|
||||||
|
// Different from lib.dom.d.ts. Added Promise<void>
|
||||||
|
handleEvent(evt: Event): void | Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EventListenerOrEventListenerObject =
|
||||||
|
| EventListener
|
||||||
|
| EventListenerObject;
|
||||||
|
|
||||||
|
// This is actually not part of actual DOM types,
|
||||||
|
// but an implementation specific thing on our custom EventTarget
|
||||||
|
// (due to the presence of our custom symbols)
|
||||||
|
export interface EventTargetListener {
|
||||||
|
callback: EventListenerOrEventListenerObject;
|
||||||
|
options: AddEventListenerOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EventTarget {
|
export interface EventTarget {
|
||||||
|
// TODO: below 4 symbol props should not present on EventTarget WebIDL.
|
||||||
|
// They should be implementation specific details.
|
||||||
[eventTargetHost]: EventTarget | null;
|
[eventTargetHost]: EventTarget | null;
|
||||||
[eventTargetListeners]: { [type in string]: EventListener[] };
|
[eventTargetListeners]: { [type in string]: EventTargetListener[] };
|
||||||
[eventTargetMode]: string;
|
[eventTargetMode]: string;
|
||||||
[eventTargetNodeType]: NodeType;
|
[eventTargetNodeType]: NodeType;
|
||||||
addEventListener(
|
addEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: Event) => void | null,
|
listener: EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | AddEventListenerOptions
|
options?: boolean | AddEventListenerOptions
|
||||||
): void;
|
): void;
|
||||||
dispatchEvent(event: Event): boolean;
|
dispatchEvent(event: Event): boolean;
|
||||||
removeEventListener(
|
removeEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback?: (event: Event) => void | null,
|
listener: EventListenerOrEventListenerObject | null,
|
||||||
options?: EventListenerOptions | boolean
|
options?: EventListenerOptions | boolean
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
@ -147,12 +171,6 @@ export interface URLSearchParams extends DomIterable<string, string> {
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventListener {
|
|
||||||
handleEvent(event: Event): void;
|
|
||||||
readonly callback: (event: Event) => void | null;
|
|
||||||
readonly options: boolean | AddEventListenerOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EventInit {
|
export interface EventInit {
|
||||||
bubbles?: boolean;
|
bubbles?: boolean;
|
||||||
cancelable?: boolean;
|
cancelable?: boolean;
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const eventTargetHasActivationBehavior: unique symbol = Symbol();
|
||||||
export class EventTarget implements domTypes.EventTarget {
|
export class EventTarget implements domTypes.EventTarget {
|
||||||
public [domTypes.eventTargetHost]: domTypes.EventTarget | null = null;
|
public [domTypes.eventTargetHost]: domTypes.EventTarget | null = null;
|
||||||
public [domTypes.eventTargetListeners]: {
|
public [domTypes.eventTargetListeners]: {
|
||||||
[type in string]: domTypes.EventListener[];
|
[type in string]: domTypes.EventTargetListener[];
|
||||||
} = {};
|
} = {};
|
||||||
public [domTypes.eventTargetMode] = "";
|
public [domTypes.eventTargetMode] = "";
|
||||||
public [domTypes.eventTargetNodeType]: domTypes.NodeType =
|
public [domTypes.eventTargetNodeType]: domTypes.NodeType =
|
||||||
|
@ -35,7 +35,7 @@ export class EventTarget implements domTypes.EventTarget {
|
||||||
|
|
||||||
public addEventListener(
|
public addEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: domTypes.Event) => void | null,
|
callback: domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: domTypes.AddEventListenerOptions | boolean
|
options?: domTypes.AddEventListenerOptions | boolean
|
||||||
): void {
|
): void {
|
||||||
const this_ = this || globalThis;
|
const this_ = this || globalThis;
|
||||||
|
@ -68,20 +68,15 @@ export class EventTarget implements domTypes.EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
||||||
const eventTarget = this;
|
|
||||||
listeners[type].push({
|
listeners[type].push({
|
||||||
callback,
|
callback,
|
||||||
options: normalizedOptions,
|
options: normalizedOptions
|
||||||
handleEvent(event: domTypes.Event): void {
|
});
|
||||||
this.callback.call(eventTarget, event);
|
|
||||||
}
|
|
||||||
} as domTypes.EventListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeEventListener(
|
public removeEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: domTypes.Event) => void | null,
|
callback: domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: domTypes.EventListenerOptions | boolean
|
options?: domTypes.EventListenerOptions | boolean
|
||||||
): void {
|
): void {
|
||||||
const this_ = this || globalThis;
|
const this_ = this || globalThis;
|
||||||
|
@ -359,7 +354,7 @@ const eventTargetHelpers = {
|
||||||
innerInvokeEventListeners(
|
innerInvokeEventListeners(
|
||||||
targetImpl: EventTarget,
|
targetImpl: EventTarget,
|
||||||
eventImpl: domTypes.Event,
|
eventImpl: domTypes.Event,
|
||||||
targetListeners: { [type in string]: domTypes.EventListener[] }
|
targetListeners: { [type in string]: domTypes.EventTargetListener[] }
|
||||||
): boolean {
|
): boolean {
|
||||||
let found = false;
|
let found = false;
|
||||||
|
|
||||||
|
@ -413,7 +408,13 @@ const eventTargetHelpers = {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
listener.handleEvent(eventImpl);
|
if (typeof listener.callback === "object") {
|
||||||
|
if (typeof listener.callback.handleEvent === "function") {
|
||||||
|
listener.callback.handleEvent(eventImpl);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listener.callback.call(eventImpl.currentTarget, eventImpl);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// TODO(bartlomieju): very likely that different error
|
// TODO(bartlomieju): very likely that different error
|
||||||
// should be thrown here (DOMException?)
|
// should be thrown here (DOMException?)
|
||||||
|
|
|
@ -39,7 +39,7 @@ unitTest(function anEventTargetCanBeSubclassed(): void {
|
||||||
class NicerEventTarget extends EventTarget {
|
class NicerEventTarget extends EventTarget {
|
||||||
on(
|
on(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (e: Event) => void | null,
|
callback: ((e: Event) => void) | null,
|
||||||
options?: __domTypes.AddEventListenerOptions
|
options?: __domTypes.AddEventListenerOptions
|
||||||
): void {
|
): void {
|
||||||
this.addEventListener(type, callback, options);
|
this.addEventListener(type, callback, options);
|
||||||
|
@ -47,7 +47,7 @@ unitTest(function anEventTargetCanBeSubclassed(): void {
|
||||||
|
|
||||||
off(
|
off(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (e: Event) => void | null,
|
callback: ((e: Event) => void) | null,
|
||||||
options?: __domTypes.EventListenerOptions
|
options?: __domTypes.EventListenerOptions
|
||||||
): void {
|
): void {
|
||||||
this.removeEventListener(type, callback, options);
|
this.removeEventListener(type, callback, options);
|
||||||
|
@ -154,3 +154,78 @@ unitTest(function eventTargetThisShouldDefaultToWindow(): void {
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
assertEquals(n, 1);
|
assertEquals(n, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(function eventTargetShouldAcceptEventListenerObject(): void {
|
||||||
|
const target = new EventTarget();
|
||||||
|
const event = new Event("foo", { bubbles: true, cancelable: false });
|
||||||
|
let callCount = 0;
|
||||||
|
|
||||||
|
const listener = {
|
||||||
|
handleEvent(e: Event): void {
|
||||||
|
assertEquals(e, event);
|
||||||
|
++callCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
target.addEventListener("foo", listener);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 1);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
|
||||||
|
target.removeEventListener("foo", listener);
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function eventTargetShouldAcceptAsyncFunction(): void {
|
||||||
|
const target = new EventTarget();
|
||||||
|
const event = new Event("foo", { bubbles: true, cancelable: false });
|
||||||
|
let callCount = 0;
|
||||||
|
|
||||||
|
const listener = async (e: Event): Promise<void> => {
|
||||||
|
assertEquals(e, event);
|
||||||
|
++callCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
target.addEventListener("foo", listener);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 1);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
|
||||||
|
target.removeEventListener("foo", listener);
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
function eventTargetShouldAcceptAsyncFunctionForEventListenerObject(): void {
|
||||||
|
const target = new EventTarget();
|
||||||
|
const event = new Event("foo", { bubbles: true, cancelable: false });
|
||||||
|
let callCount = 0;
|
||||||
|
|
||||||
|
const listener = {
|
||||||
|
async handleEvent(e: Event): Promise<void> {
|
||||||
|
assertEquals(e, event);
|
||||||
|
++callCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
target.addEventListener("foo", listener);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 1);
|
||||||
|
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
|
||||||
|
target.removeEventListener("foo", listener);
|
||||||
|
target.dispatchEvent(event);
|
||||||
|
assertEquals(callCount, 2);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -104,7 +104,7 @@ declare global {
|
||||||
/* eslint-disable no-var */
|
/* eslint-disable no-var */
|
||||||
var addEventListener: (
|
var addEventListener: (
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: domTypes.Event) => void | null,
|
callback: domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | domTypes.AddEventListenerOptions | undefined
|
options?: boolean | domTypes.AddEventListenerOptions | undefined
|
||||||
) => void;
|
) => void;
|
||||||
var queueMicrotask: (callback: () => void) => void;
|
var queueMicrotask: (callback: () => void) => void;
|
||||||
|
|
51
cli/js/lib.deno.shared_globals.d.ts
vendored
51
cli/js/lib.deno.shared_globals.d.ts
vendored
|
@ -42,13 +42,13 @@ declare interface WindowOrWorkerGlobalScope {
|
||||||
|
|
||||||
addEventListener: (
|
addEventListener: (
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | __domTypes.AddEventListenerOptions | undefined
|
options?: boolean | __domTypes.AddEventListenerOptions | undefined
|
||||||
) => void;
|
) => void;
|
||||||
dispatchEvent: (event: __domTypes.Event) => boolean;
|
dispatchEvent: (event: __domTypes.Event) => boolean;
|
||||||
removeEventListener: (
|
removeEventListener: (
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | __domTypes.EventListenerOptions | undefined
|
options?: boolean | __domTypes.EventListenerOptions | undefined
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ declare const CustomEventInit: typeof __customEvent.CustomEventInit;
|
||||||
declare const CustomEvent: typeof __customEvent.CustomEvent;
|
declare const CustomEvent: typeof __customEvent.CustomEvent;
|
||||||
declare const EventInit: typeof __event.EventInit;
|
declare const EventInit: typeof __event.EventInit;
|
||||||
declare const Event: typeof __event.Event;
|
declare const Event: typeof __event.Event;
|
||||||
declare const EventListener: typeof __eventTarget.EventListener;
|
declare const EventListener: __domTypes.EventListener;
|
||||||
declare const EventTarget: typeof __eventTarget.EventTarget;
|
declare const EventTarget: typeof __eventTarget.EventTarget;
|
||||||
declare const URL: typeof __url.URL;
|
declare const URL: typeof __url.URL;
|
||||||
declare const URLSearchParams: typeof __urlSearchParams.URLSearchParams;
|
declare const URLSearchParams: typeof __urlSearchParams.URLSearchParams;
|
||||||
|
@ -256,13 +256,13 @@ declare const Worker: typeof __workers.WorkerImpl;
|
||||||
|
|
||||||
declare const addEventListener: (
|
declare const addEventListener: (
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | __domTypes.AddEventListenerOptions | undefined
|
options?: boolean | __domTypes.AddEventListenerOptions | undefined
|
||||||
) => void;
|
) => void;
|
||||||
declare const dispatchEvent: (event: __domTypes.Event) => boolean;
|
declare const dispatchEvent: (event: __domTypes.Event) => boolean;
|
||||||
declare const removeEventListener: (
|
declare const removeEventListener: (
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | __domTypes.EventListenerOptions | undefined
|
options?: boolean | __domTypes.EventListenerOptions | undefined
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
|
@ -346,6 +346,19 @@ declare namespace __domTypes {
|
||||||
export const eventTargetListeners: unique symbol;
|
export const eventTargetListeners: unique symbol;
|
||||||
export const eventTargetMode: unique symbol;
|
export const eventTargetMode: unique symbol;
|
||||||
export const eventTargetNodeType: unique symbol;
|
export const eventTargetNodeType: unique symbol;
|
||||||
|
export interface EventListener {
|
||||||
|
(evt: Event): void | Promise<void>;
|
||||||
|
}
|
||||||
|
export interface EventListenerObject {
|
||||||
|
handleEvent(evt: Event): void | Promise<void>;
|
||||||
|
}
|
||||||
|
export type EventListenerOrEventListenerObject =
|
||||||
|
| EventListener
|
||||||
|
| EventListenerObject;
|
||||||
|
export interface EventTargetListener {
|
||||||
|
callback: EventListenerOrEventListenerObject;
|
||||||
|
options: AddEventListenerOptions;
|
||||||
|
}
|
||||||
export interface EventTarget {
|
export interface EventTarget {
|
||||||
[eventTargetHost]: EventTarget | null;
|
[eventTargetHost]: EventTarget | null;
|
||||||
[eventTargetListeners]: { [type in string]: EventListener[] };
|
[eventTargetListeners]: { [type in string]: EventListener[] };
|
||||||
|
@ -353,13 +366,13 @@ declare namespace __domTypes {
|
||||||
[eventTargetNodeType]: NodeType;
|
[eventTargetNodeType]: NodeType;
|
||||||
addEventListener(
|
addEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: Event) => void | null,
|
callback: EventListenerOrEventListenerObject | null,
|
||||||
options?: boolean | AddEventListenerOptions
|
options?: boolean | AddEventListenerOptions
|
||||||
): void;
|
): void;
|
||||||
dispatchEvent(event: Event): boolean;
|
dispatchEvent(event: Event): boolean;
|
||||||
removeEventListener(
|
removeEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback?: (event: Event) => void | null,
|
callback?: EventListenerOrEventListenerObject | null,
|
||||||
options?: EventListenerOptions | boolean
|
options?: EventListenerOptions | boolean
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
@ -414,11 +427,6 @@ declare namespace __domTypes {
|
||||||
thisArg?: any
|
thisArg?: any
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
export interface EventListener {
|
|
||||||
handleEvent(event: Event): void;
|
|
||||||
readonly callback: (event: Event) => void | null;
|
|
||||||
readonly options: boolean | AddEventListenerOptions;
|
|
||||||
}
|
|
||||||
export interface EventInit {
|
export interface EventInit {
|
||||||
bubbles?: boolean;
|
bubbles?: boolean;
|
||||||
cancelable?: boolean;
|
cancelable?: boolean;
|
||||||
|
@ -1095,21 +1103,6 @@ declare namespace __eventTarget {
|
||||||
readonly passive: boolean;
|
readonly passive: boolean;
|
||||||
readonly once: boolean;
|
readonly once: boolean;
|
||||||
}
|
}
|
||||||
export class EventListener implements __domTypes.EventListener {
|
|
||||||
allEvents: __domTypes.Event[];
|
|
||||||
atEvents: __domTypes.Event[];
|
|
||||||
bubbledEvents: __domTypes.Event[];
|
|
||||||
capturedEvents: __domTypes.Event[];
|
|
||||||
private _callback;
|
|
||||||
private _options;
|
|
||||||
constructor(
|
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
|
||||||
options: boolean | __domTypes.AddEventListenerOptions
|
|
||||||
);
|
|
||||||
handleEvent(event: __domTypes.Event): void;
|
|
||||||
readonly callback: (event: __domTypes.Event) => void | null;
|
|
||||||
readonly options: __domTypes.AddEventListenerOptions | boolean;
|
|
||||||
}
|
|
||||||
export const eventTargetAssignedSlot: unique symbol;
|
export const eventTargetAssignedSlot: unique symbol;
|
||||||
export const eventTargetHasActivationBehavior: unique symbol;
|
export const eventTargetHasActivationBehavior: unique symbol;
|
||||||
export class EventTarget implements __domTypes.EventTarget {
|
export class EventTarget implements __domTypes.EventTarget {
|
||||||
|
@ -1123,12 +1116,12 @@ declare namespace __eventTarget {
|
||||||
private [eventTargetHasActivationBehavior];
|
private [eventTargetHasActivationBehavior];
|
||||||
addEventListener(
|
addEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: __domTypes.AddEventListenerOptions | boolean
|
options?: __domTypes.AddEventListenerOptions | boolean
|
||||||
): void;
|
): void;
|
||||||
removeEventListener(
|
removeEventListener(
|
||||||
type: string,
|
type: string,
|
||||||
callback: (event: __domTypes.Event) => void | null,
|
callback: __domTypes.EventListenerOrEventListenerObject | null,
|
||||||
options?: __domTypes.EventListenerOptions | boolean
|
options?: __domTypes.EventListenerOptions | boolean
|
||||||
): void;
|
): void;
|
||||||
dispatchEvent(event: __domTypes.Event): boolean;
|
dispatchEvent(event: __domTypes.Event): boolean;
|
||||||
|
|
Loading…
Reference in a new issue