Web API: CustomEvent (#1505)

This commit is contained in:
Adam Conrad 2019-01-23 12:20:53 +00:00 committed by Ryan Dahl
parent 77114fbda4
commit e470f31d32
8 changed files with 132 additions and 2 deletions

View file

@ -56,6 +56,7 @@ ts_sources = [
"js/compiler.ts", "js/compiler.ts",
"js/console.ts", "js/console.ts",
"js/copy_file.ts", "js/copy_file.ts",
"js/custom_event.ts",
"js/deno.ts", "js/deno.ts",
"js/dir.ts", "js/dir.ts",
"js/dispatch.ts", "js/dispatch.ts",

60
js/custom_event.ts Normal file
View file

@ -0,0 +1,60 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as domTypes from "./dom_types";
import * as event from "./event";
import { getPrivateValue } from "./util";
// WeakMaps are recommended for private attributes (see MDN link below)
// tslint:disable-next-line:max-line-length
// https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Add-on_SDK/Guides/Contributor_s_Guide/Private_Properties#Using_WeakMaps
export const customEventAttributes = new WeakMap();
export class CustomEventInit extends event.EventInit
implements domTypes.CustomEventInit {
// tslint:disable-next-line:no-any
detail: any;
constructor({
bubbles = false,
cancelable = false,
composed = false,
detail = null
}: domTypes.CustomEventInit) {
super({ bubbles, cancelable, composed });
this.detail = detail;
}
}
export class CustomEvent extends event.Event implements domTypes.CustomEvent {
constructor(
type: string,
customEventInitDict: domTypes.CustomEventInit = {}
) {
super(type, customEventInitDict);
const { detail = null } = customEventInitDict;
customEventAttributes.set(this, { detail });
}
// tslint:disable-next-line:no-any
get detail(): any {
return getPrivateValue(this, customEventAttributes, "detail");
}
initCustomEvent(
type: string,
bubbles?: boolean,
cancelable?: boolean,
// tslint:disable-next-line:no-any
detail?: any
) {
if (this.dispatched) {
return;
}
customEventAttributes.set(this, { detail });
}
}
/** Built-in objects providing `get` methods for our
* interceptable JavaScript operations.
*/
Reflect.defineProperty(CustomEvent.prototype, "detail", { enumerable: true });

21
js/custom_event_test.ts Normal file
View file

@ -0,0 +1,21 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import { test, assertEqual } from "./test_util.ts";
test(function customEventInitializedWithDetail() {
const type = "touchstart";
const detail = { message: "hello" };
const customEventDict = new CustomEventInit({
bubbles: true,
cancelable: true,
detail
});
const event = new CustomEvent(type, customEventDict);
assertEqual(event.bubbles, true);
assertEqual(event.cancelable, true);
assertEqual(event.currentTarget, null);
assertEqual(event.detail, detail);
assertEqual(event.isTrusted, false);
assertEqual(event.target, null);
assertEqual(event.type, type);
});

View file

@ -144,6 +144,11 @@ export interface EventInit {
composed?: boolean; composed?: boolean;
} }
export interface CustomEventInit extends EventInit {
// tslint:disable-next-line:no-any
detail?: any;
}
export enum EventPhase { export enum EventPhase {
NONE = 0, NONE = 0,
CAPTURING_PHASE = 1, CAPTURING_PHASE = 1,
@ -182,6 +187,18 @@ export interface Event {
readonly timeStamp: Date; readonly timeStamp: Date;
} }
export interface CustomEvent extends Event {
// tslint:disable-next-line:no-any
readonly detail: any;
initCustomEvent(
type: string,
bubbles?: boolean,
cancelable?: boolean,
// tslint:disable-next-line:no-any
detail?: any | null
): void;
}
/* TODO(ry) Re-expose this interface. There is currently some interference /* TODO(ry) Re-expose this interface. There is currently some interference
* between deno's File and this one. * between deno's File and this one.
*/ */

View file

@ -22,6 +22,8 @@ export class EventInit implements domTypes.EventInit {
export class Event implements domTypes.Event { export class Event implements domTypes.Event {
// Each event has the following associated flags // Each event has the following associated flags
private _canceledFlag = false; private _canceledFlag = false;
private _dispatchedFlag = false;
private _initializedFlag = false;
private _inPassiveListenerFlag = false; private _inPassiveListenerFlag = false;
private _stopImmediatePropagationFlag = false; private _stopImmediatePropagationFlag = false;
private _stopPropagationFlag = false; private _stopPropagationFlag = false;
@ -30,6 +32,7 @@ export class Event implements domTypes.Event {
private _path: domTypes.EventPath[] = []; private _path: domTypes.EventPath[] = [];
constructor(type: string, eventInitDict: domTypes.EventInit = {}) { constructor(type: string, eventInitDict: domTypes.EventInit = {}) {
this._initializedFlag = true;
eventAttributes.set(this, { eventAttributes.set(this, {
type, type,
bubbles: eventInitDict.bubbles || false, bubbles: eventInitDict.bubbles || false,
@ -71,14 +74,36 @@ export class Event implements domTypes.Event {
return this._canceledFlag; return this._canceledFlag;
} }
get dispatched(): boolean {
return this._dispatchedFlag;
}
get eventPhase(): number { get eventPhase(): number {
return getPrivateValue(this, eventAttributes, "eventPhase"); return getPrivateValue(this, eventAttributes, "eventPhase");
} }
get initialized(): boolean {
return this._initializedFlag;
}
get isTrusted(): boolean { get isTrusted(): boolean {
return getPrivateValue(this, eventAttributes, "isTrusted"); return getPrivateValue(this, eventAttributes, "isTrusted");
} }
set isTrusted(value) {
eventAttributes.set(this, {
type: this.type,
bubbles: this.bubbles,
cancelable: this.cancelable,
composed: this.composed,
currentTarget: this.currentTarget,
eventPhase: this.eventPhase,
isTrusted: value,
target: this.target,
timeStamp: this.timeStamp
});
}
get target(): domTypes.EventTarget { get target(): domTypes.EventTarget {
return getPrivateValue(this, eventAttributes, "target"); return getPrivateValue(this, eventAttributes, "target");
} }

View file

@ -34,8 +34,8 @@ test(function constructedEventTargetCanBeUsedAsExpected() {
test(function anEventTargetCanBeSubclassed() { test(function anEventTargetCanBeSubclassed() {
class NicerEventTarget extends EventTarget { class NicerEventTarget extends EventTarget {
on(type, listener?, options?) { on(type, callback?, options?) {
this.addEventListener(type, listener, options); this.addEventListener(type, callback, options);
} }
off(type, callback?, options?) { off(type, callback?, options?) {

View file

@ -9,6 +9,7 @@
// can be expressed as a namespace in the type library. // can be expressed as a namespace in the type library.
import * as blob from "./blob"; import * as blob from "./blob";
import * as consoleTypes from "./console"; import * as consoleTypes from "./console";
import * as customEvent from "./custom_event";
import * as domTypes from "./dom_types"; import * as domTypes from "./dom_types";
import * as event from "./event"; import * as event from "./event";
import * as eventTarget from "./event_target"; import * as eventTarget from "./event_target";
@ -64,6 +65,10 @@ export type Blob = blob.DenoBlob;
// window.File = file.DenoFile; // window.File = file.DenoFile;
// export type File = file.DenoFile; // export type File = file.DenoFile;
window.CustomEventInit = customEvent.CustomEventInit;
export type CustomEventInit = customEvent.CustomEventInit;
window.CustomEvent = customEvent.CustomEvent;
export type CustomEvent = customEvent.CustomEvent;
window.EventInit = event.EventInit; window.EventInit = event.EventInit;
export type EventInit = event.EventInit; export type EventInit = event.EventInit;
window.Event = event.Event; window.Event = event.Event;

View file

@ -9,6 +9,7 @@ import "./chmod_test.ts";
import "./compiler_test.ts"; import "./compiler_test.ts";
import "./console_test.ts"; import "./console_test.ts";
import "./copy_file_test.ts"; import "./copy_file_test.ts";
import "./custom_event_test.ts";
import "./dir_test.ts"; import "./dir_test.ts";
import "./event_test.ts"; import "./event_test.ts";
import "./event_target_test.ts"; import "./event_target_test.ts";