mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 08:33:43 -05:00
refactor: Event and EventTarget implementations (#4707)
Refactors Event and EventTarget so that they better encapsulate their non-public data as well as are more forward compatible with things like DOM Nodes. Moves `dom_types.ts` -> `dom_types.d.ts` which was always the intention, it was a legacy of when we used to build the types from the code and the limitations of the compiler. There was a lot of cruft in `dom_types` which shouldn't have been there, and mis-alignment to the DOM standards. This generally has been eliminated, though we still have some minor differences from the DOM (like the removal of some deprecated methods/properties). Adds `DOMException`. Strictly it shouldn't inherit from `Error`, but most browsers provide a stack trace when one is thrown, so the behaviour in Deno actually better matches the browser. `Event` still doesn't log to console like it does in the browser. I wanted to get this raised and that could be an enhancement later on (it currently doesn't either).
This commit is contained in:
parent
2b362bef85
commit
fc4819e1e0
40 changed files with 1205 additions and 1120 deletions
|
@ -1,10 +1,12 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import "./lib.deno.shared_globals.d.ts";
|
||||
|
||||
import * as blob from "./web/blob.ts";
|
||||
import * as consoleTypes from "./web/console.ts";
|
||||
import * as promiseTypes from "./web/promise.ts";
|
||||
import * as customEvent from "./web/custom_event.ts";
|
||||
import * as domTypes from "./web/dom_types.ts";
|
||||
import * as domException from "./web/dom_exception.ts";
|
||||
import * as domFile from "./web/dom_file.ts";
|
||||
import * as event from "./web/event.ts";
|
||||
import * as eventTarget from "./web/event_target.ts";
|
||||
|
@ -123,21 +125,13 @@ declare global {
|
|||
// Only `var` variables show up in the `globalThis` type when doing a global
|
||||
// scope augmentation.
|
||||
/* eslint-disable no-var */
|
||||
var addEventListener: (
|
||||
type: string,
|
||||
callback: domTypes.EventListenerOrEventListenerObject | null,
|
||||
options?: boolean | domTypes.AddEventListenerOptions | undefined
|
||||
) => void;
|
||||
var queueMicrotask: (callback: () => void) => void;
|
||||
var console: consoleTypes.Console;
|
||||
var location: domTypes.Location;
|
||||
|
||||
// Assigned to `window` global - main runtime
|
||||
var Deno: {
|
||||
core: DenoCore;
|
||||
};
|
||||
var onload: ((e: domTypes.Event) => void) | undefined;
|
||||
var onunload: ((e: domTypes.Event) => void) | undefined;
|
||||
var onload: ((e: Event) => void) | undefined;
|
||||
var onunload: ((e: Event) => void) | undefined;
|
||||
var bootstrapMainRuntime: (() => void) | undefined;
|
||||
|
||||
// Assigned to `self` global - worker runtime and compiler
|
||||
|
@ -150,7 +144,7 @@ declare global {
|
|||
source: string,
|
||||
lineno: number,
|
||||
colno: number,
|
||||
e: domTypes.Event
|
||||
e: Event
|
||||
) => boolean | void)
|
||||
| undefined;
|
||||
|
||||
|
@ -163,9 +157,6 @@ declare global {
|
|||
// Assigned to `self` global - compiler
|
||||
var bootstrapTsCompilerRuntime: (() => void) | undefined;
|
||||
var bootstrapWasmCompilerRuntime: (() => void) | undefined;
|
||||
|
||||
var performance: performanceUtil.Performance;
|
||||
var setTimeout: typeof timers.setTimeout;
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
|
@ -218,9 +209,10 @@ export const windowOrWorkerGlobalScopeProperties = {
|
|||
console: writable(new consoleTypes.Console(core.print)),
|
||||
Blob: nonEnumerable(blob.DenoBlob),
|
||||
File: nonEnumerable(domFile.DomFileImpl),
|
||||
CustomEvent: nonEnumerable(customEvent.CustomEvent),
|
||||
Event: nonEnumerable(event.Event),
|
||||
EventTarget: nonEnumerable(eventTarget.EventTarget),
|
||||
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
|
||||
DOMException: nonEnumerable(domException.DOMExceptionImpl),
|
||||
Event: nonEnumerable(event.EventImpl),
|
||||
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
|
||||
URL: nonEnumerable(url.URL),
|
||||
URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParams),
|
||||
Headers: nonEnumerable(headers.Headers),
|
||||
|
@ -234,19 +226,17 @@ export const windowOrWorkerGlobalScopeProperties = {
|
|||
Worker: nonEnumerable(workers.WorkerImpl),
|
||||
};
|
||||
|
||||
export const eventTargetProperties = {
|
||||
[domTypes.eventTargetHost]: nonEnumerable(null),
|
||||
[domTypes.eventTargetListeners]: nonEnumerable({}),
|
||||
[domTypes.eventTargetMode]: nonEnumerable(""),
|
||||
[domTypes.eventTargetNodeType]: nonEnumerable(0),
|
||||
[eventTarget.eventTargetAssignedSlot]: nonEnumerable(false),
|
||||
[eventTarget.eventTargetHasActivationBehavior]: nonEnumerable(false),
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function setEventTargetData(value: any): void {
|
||||
eventTarget.eventTargetData.set(value, eventTarget.getDefaultTargetData());
|
||||
}
|
||||
|
||||
export const eventTargetProperties = {
|
||||
addEventListener: readOnly(
|
||||
eventTarget.EventTarget.prototype.addEventListener
|
||||
eventTarget.EventTargetImpl.prototype.addEventListener
|
||||
),
|
||||
dispatchEvent: readOnly(eventTarget.EventTarget.prototype.dispatchEvent),
|
||||
dispatchEvent: readOnly(eventTarget.EventTargetImpl.prototype.dispatchEvent),
|
||||
removeEventListener: readOnly(
|
||||
eventTarget.EventTarget.prototype.removeEventListener
|
||||
eventTarget.EventTargetImpl.prototype.removeEventListener
|
||||
),
|
||||
};
|
||||
|
|
226
cli/js/lib.deno.shared_globals.d.ts
vendored
226
cli/js/lib.deno.shared_globals.d.ts
vendored
|
@ -1,12 +1,8 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, no-var */
|
||||
|
||||
/// <reference no-default-lib="true" />
|
||||
// TODO: we need to remove this, but Fetch::Response::Body implements Reader
|
||||
// which requires Deno.EOF, and we shouldn't be leaking that, but https_proxy
|
||||
// at the least requires the Reader interface on Body, which it shouldn't
|
||||
/// <reference lib="deno.ns" />
|
||||
/// <reference lib="esnext" />
|
||||
|
||||
// This follows the WebIDL at: https://webassembly.github.io/spec/js-api/
|
||||
|
@ -184,6 +180,7 @@ declare function setTimeout(
|
|||
delay?: number,
|
||||
...args: unknown[]
|
||||
): number;
|
||||
|
||||
/** Repeatedly calls a function , with a fixed time delay between each call. */
|
||||
declare function setInterval(
|
||||
cb: (...args: unknown[]) => void,
|
||||
|
@ -194,8 +191,8 @@ declare function clearTimeout(id?: number): void;
|
|||
declare function clearInterval(id?: number): void;
|
||||
declare function queueMicrotask(func: Function): void;
|
||||
|
||||
declare const console: Console;
|
||||
declare const location: Location;
|
||||
declare var console: Console;
|
||||
declare var location: Location;
|
||||
|
||||
declare function addEventListener(
|
||||
type: string,
|
||||
|
@ -315,6 +312,12 @@ interface DOMStringList {
|
|||
[index: number]: string;
|
||||
}
|
||||
|
||||
declare class DOMException extends Error {
|
||||
constructor(message?: string, name?: string);
|
||||
readonly name: string;
|
||||
readonly message: string;
|
||||
}
|
||||
|
||||
/** The location (URL) of the object it is linked to. Changes done on it are
|
||||
* reflected on the object it relates to. Both the Document and Window
|
||||
* interface have such a linked Location, accessible via Document.location and
|
||||
|
@ -1060,122 +1063,81 @@ declare namespace performance {
|
|||
export function now(): number;
|
||||
}
|
||||
|
||||
/** An event which takes place in the DOM. */
|
||||
interface Event {
|
||||
/**
|
||||
* Returns true or false depending on how event was initialized. True if
|
||||
* event goes through its target's ancestors in reverse tree order, and
|
||||
* false otherwise.
|
||||
*/
|
||||
readonly bubbles: boolean;
|
||||
|
||||
// TODO(ry) Remove cancelBubbleImmediately - non-standard extension.
|
||||
cancelBubbleImmediately: boolean;
|
||||
|
||||
cancelBubble: boolean;
|
||||
/**
|
||||
* Returns true or false depending on how event was initialized. Its return
|
||||
* value does not always carry meaning, but true can indicate that part of
|
||||
* the operation during which event was dispatched, can be canceled by
|
||||
* invoking the preventDefault() method.
|
||||
*/
|
||||
readonly cancelable: boolean;
|
||||
/**
|
||||
* Returns true or false depending on how event was initialized. True if
|
||||
* event invokes listeners past a ShadowRoot node that is the root of its
|
||||
* target, and false otherwise.
|
||||
*/
|
||||
readonly composed: boolean;
|
||||
/**
|
||||
* Returns the object whose event listener's callback is currently being
|
||||
* invoked.
|
||||
*/
|
||||
readonly currentTarget: EventTarget | null;
|
||||
/**
|
||||
* Returns true if preventDefault() was invoked successfully to indicate
|
||||
* cancelation, and false otherwise.
|
||||
*/
|
||||
readonly defaultPrevented: boolean;
|
||||
/**
|
||||
* Returns the event's phase, which is one of NONE, CAPTURING_PHASE,
|
||||
* AT_TARGET, and BUBBLING_PHASE.
|
||||
*/
|
||||
readonly eventPhase: number;
|
||||
/**
|
||||
* Returns true if event was dispatched by the user agent, and false
|
||||
* otherwise.
|
||||
*/
|
||||
readonly isTrusted: boolean;
|
||||
returnValue: boolean;
|
||||
/** @deprecated */
|
||||
readonly srcElement: EventTarget | null;
|
||||
/**
|
||||
* Returns the object to which event is dispatched (its target).
|
||||
*/
|
||||
readonly target: EventTarget | null;
|
||||
/**
|
||||
* Returns the event's timestamp as the number of milliseconds measured
|
||||
* relative to the time origin.
|
||||
*/
|
||||
readonly timeStamp: number;
|
||||
/**
|
||||
* Returns the type of event, e.g. "click", "hashchange", or "submit".
|
||||
*/
|
||||
readonly type: string;
|
||||
/**
|
||||
* Returns the invocation target objects of event's path (objects on which
|
||||
* listeners will be invoked), except for any nodes in shadow trees of which
|
||||
* the shadow root's mode is "closed" that are not reachable from event's
|
||||
* currentTarget.
|
||||
*/
|
||||
composedPath(): EventTarget[];
|
||||
initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;
|
||||
/**
|
||||
* If invoked when the cancelable attribute value is true, and while
|
||||
* executing a listener for the event with passive set to false, signals to
|
||||
* the operation that caused event to be dispatched that it needs to be
|
||||
* canceled.
|
||||
*/
|
||||
preventDefault(): void;
|
||||
/**
|
||||
* Invoking this method prevents event from reaching any registered event
|
||||
* listeners after the current one finishes running and, when dispatched in
|
||||
* a tree, also prevents event from reaching any other objects.
|
||||
*/
|
||||
stopImmediatePropagation(): void;
|
||||
/**
|
||||
* When dispatched in a tree, invoking this method prevents event from
|
||||
* reaching any objects other than the current object.
|
||||
*/
|
||||
stopPropagation(): void;
|
||||
readonly AT_TARGET: number;
|
||||
readonly BUBBLING_PHASE: number;
|
||||
readonly CAPTURING_PHASE: number;
|
||||
readonly NONE: number;
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
bubbles?: boolean;
|
||||
cancelable?: boolean;
|
||||
composed?: boolean;
|
||||
}
|
||||
|
||||
declare const Event: {
|
||||
prototype: Event;
|
||||
new (type: string, eventInitDict?: EventInit): Event;
|
||||
/** An event which takes place in the DOM. */
|
||||
declare class Event {
|
||||
constructor(type: string, eventInitDict?: EventInit);
|
||||
/** Returns true or false depending on how event was initialized. True if
|
||||
* event goes through its target's ancestors in reverse tree order, and
|
||||
* false otherwise. */
|
||||
readonly bubbles: boolean;
|
||||
cancelBubble: boolean;
|
||||
/** Returns true or false depending on how event was initialized. Its return
|
||||
* value does not always carry meaning, but true can indicate that part of the
|
||||
* operation during which event was dispatched, can be canceled by invoking
|
||||
* the preventDefault() method. */
|
||||
readonly cancelable: boolean;
|
||||
/** Returns true or false depending on how event was initialized. True if
|
||||
* event invokes listeners past a ShadowRoot node that is the root of its
|
||||
* target, and false otherwise. */
|
||||
readonly composed: boolean;
|
||||
/** Returns the object whose event listener's callback is currently being
|
||||
* invoked. */
|
||||
readonly currentTarget: EventTarget | null;
|
||||
/** Returns true if preventDefault() was invoked successfully to indicate
|
||||
* cancellation, and false otherwise. */
|
||||
readonly defaultPrevented: boolean;
|
||||
/** Returns the event's phase, which is one of NONE, CAPTURING_PHASE,
|
||||
* AT_TARGET, and BUBBLING_PHASE. */
|
||||
readonly eventPhase: number;
|
||||
/** Returns true if event was dispatched by the user agent, and false
|
||||
* otherwise. */
|
||||
readonly isTrusted: boolean;
|
||||
/** Returns the object to which event is dispatched (its target). */
|
||||
readonly target: EventTarget | null;
|
||||
/** Returns the event's timestamp as the number of milliseconds measured
|
||||
* relative to the time origin. */
|
||||
readonly timeStamp: number;
|
||||
/** Returns the type of event, e.g. "click", "hashchange", or "submit". */
|
||||
readonly type: string;
|
||||
/** Returns the invocation target objects of event's path (objects on which
|
||||
* listeners will be invoked), except for any nodes in shadow trees of which
|
||||
* the shadow root's mode is "closed" that are not reachable from event's
|
||||
* currentTarget. */
|
||||
composedPath(): EventTarget[];
|
||||
/** If invoked when the cancelable attribute value is true, and while
|
||||
* executing a listener for the event with passive set to false, signals to
|
||||
* the operation that caused event to be dispatched that it needs to be
|
||||
* canceled. */
|
||||
preventDefault(): void;
|
||||
/** Invoking this method prevents event from reaching any registered event
|
||||
* listeners after the current one finishes running and, when dispatched in a
|
||||
* tree, also prevents event from reaching any other objects. */
|
||||
stopImmediatePropagation(): void;
|
||||
/** When dispatched in a tree, invoking this method prevents event from
|
||||
* reaching any objects other than the current object. */
|
||||
stopPropagation(): void;
|
||||
readonly AT_TARGET: number;
|
||||
readonly BUBBLING_PHASE: number;
|
||||
readonly CAPTURING_PHASE: number;
|
||||
readonly NONE: number;
|
||||
};
|
||||
static readonly AT_TARGET: number;
|
||||
static readonly BUBBLING_PHASE: number;
|
||||
static readonly CAPTURING_PHASE: number;
|
||||
static readonly NONE: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* EventTarget is a DOM interface implemented by objects that can receive events
|
||||
* and may have listeners for them.
|
||||
*/
|
||||
interface EventTarget {
|
||||
/**
|
||||
* Appends an event listener for events whose type attribute value is type.
|
||||
declare class EventTarget {
|
||||
/** Appends an event listener for events whose type attribute value is type.
|
||||
* The callback argument sets the callback that will be invoked when the event
|
||||
* is dispatched.
|
||||
*
|
||||
|
@ -1197,41 +1159,32 @@ interface EventTarget {
|
|||
* invoked once after which the event listener will be removed.
|
||||
*
|
||||
* The event listener is appended to target's event listener list and is not
|
||||
* appended if it has the same type, callback, and capture.
|
||||
*/
|
||||
* appended if it has the same type, callback, and capture. */
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject | null,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
/**
|
||||
* Dispatches a synthetic event event to target and returns true if either
|
||||
/** Dispatches a synthetic event event to target and returns true if either
|
||||
* event's cancelable attribute value is false or its preventDefault() method
|
||||
* was not invoked, and false otherwise.
|
||||
*/
|
||||
* was not invoked, and false otherwise. */
|
||||
dispatchEvent(event: Event): boolean;
|
||||
/**
|
||||
* Removes the event listener in target's event listener list with the same
|
||||
* type, callback, and options.
|
||||
*/
|
||||
/** Removes the event listener in target's event listener list with the same
|
||||
* type, callback, and options. */
|
||||
removeEventListener(
|
||||
type: string,
|
||||
callback: EventListenerOrEventListenerObject | null,
|
||||
options?: EventListenerOptions | boolean
|
||||
): void;
|
||||
[Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
declare const EventTarget: {
|
||||
prototype: EventTarget;
|
||||
new (): EventTarget;
|
||||
};
|
||||
|
||||
interface EventListener {
|
||||
(evt: Event): void;
|
||||
(evt: Event): void | Promise<void>;
|
||||
}
|
||||
|
||||
interface EventListenerObject {
|
||||
handleEvent(evt: Event): void;
|
||||
handleEvent(evt: Event): void | Promise<void>;
|
||||
}
|
||||
|
||||
declare type EventListenerOrEventListenerObject =
|
||||
|
@ -1257,27 +1210,16 @@ interface ProgressEvent<T extends EventTarget = EventTarget> extends Event {
|
|||
readonly total: number;
|
||||
}
|
||||
|
||||
interface CustomEvent<T = any> extends Event {
|
||||
/**
|
||||
* Returns any custom data event was created with. Typically used for synthetic events.
|
||||
*/
|
||||
readonly detail: T;
|
||||
initCustomEvent(
|
||||
typeArg: string,
|
||||
canBubbleArg: boolean,
|
||||
cancelableArg: boolean,
|
||||
detailArg: T
|
||||
): void;
|
||||
}
|
||||
|
||||
interface CustomEventInit<T = any> extends EventInit {
|
||||
detail?: T;
|
||||
}
|
||||
|
||||
declare const CustomEvent: {
|
||||
prototype: CustomEvent;
|
||||
new <T>(typeArg: string, eventInitDict?: CustomEventInit<T>): CustomEvent<T>;
|
||||
};
|
||||
declare class CustomEvent<T = any> extends Event {
|
||||
constructor(typeArg: string, eventInitDict?: CustomEventInit<T>);
|
||||
/** Returns any custom data event was created with. Typically used for
|
||||
* synthetic events. */
|
||||
readonly detail: T;
|
||||
}
|
||||
|
||||
interface AbortSignalEventMap {
|
||||
abort: Event;
|
||||
|
|
20
cli/js/lib.deno.window.d.ts
vendored
20
cli/js/lib.deno.window.d.ts
vendored
|
@ -1,28 +1,28 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/// <reference no-default-lib="true" />
|
||||
/// <reference lib="deno.ns" />
|
||||
/// <reference lib="deno.shared_globals" />
|
||||
/// <reference lib="esnext" />
|
||||
|
||||
declare interface Window {
|
||||
window: Window & typeof globalThis;
|
||||
self: Window & typeof globalThis;
|
||||
onload: Function | undefined;
|
||||
onunload: Function | undefined;
|
||||
declare interface Window extends EventTarget {
|
||||
readonly window: Window & typeof globalThis;
|
||||
readonly self: Window & typeof globalThis;
|
||||
onload: ((this: Window, ev: Event) => any) | null;
|
||||
onunload: ((this: Window, ev: Event) => any) | null;
|
||||
location: Location;
|
||||
crypto: Crypto;
|
||||
close: () => void;
|
||||
closed: boolean;
|
||||
readonly closed: boolean;
|
||||
Deno: typeof Deno;
|
||||
}
|
||||
|
||||
declare const window: Window & typeof globalThis;
|
||||
declare const self: Window & typeof globalThis;
|
||||
declare const onload: Function | undefined;
|
||||
declare const onunload: Function | undefined;
|
||||
declare const onload: ((this: Window, ev: Event) => any) | null;
|
||||
declare const onunload: ((this: Window, ev: Event) => any) | null;
|
||||
declare const crypto: Crypto;
|
||||
|
||||
declare interface Crypto {
|
||||
|
@ -45,4 +45,4 @@ declare interface Crypto {
|
|||
): T;
|
||||
}
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// It sets up runtime by providing globals for `WindowScope` and adds `Deno` global.
|
||||
|
||||
import * as Deno from "./deno.ts";
|
||||
import * as domTypes from "./web/dom_types.ts";
|
||||
import * as csprng from "./ops/get_random_values.ts";
|
||||
import { exit } from "./ops/os.ts";
|
||||
import {
|
||||
|
@ -18,6 +17,7 @@ import {
|
|||
windowOrWorkerGlobalScopeMethods,
|
||||
windowOrWorkerGlobalScopeProperties,
|
||||
eventTargetProperties,
|
||||
setEventTargetData,
|
||||
} from "./globals.ts";
|
||||
import { internalObject } from "./internals.ts";
|
||||
import { setSignals } from "./signals.ts";
|
||||
|
@ -59,9 +59,9 @@ export const mainRuntimeGlobalProperties = {
|
|||
self: readOnly(globalThis),
|
||||
crypto: readOnly(csprng),
|
||||
// TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope)
|
||||
// it seems those two properties should be availble to workers as well
|
||||
onload: writable(undefined),
|
||||
onunload: writable(undefined),
|
||||
// it seems those two properties should be available to workers as well
|
||||
onload: writable(null),
|
||||
onunload: writable(null),
|
||||
close: writable(windowClose),
|
||||
closed: getterOnly(() => windowIsClosing),
|
||||
};
|
||||
|
@ -78,15 +78,16 @@ export function bootstrapMainRuntime(): void {
|
|||
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeProperties);
|
||||
Object.defineProperties(globalThis, eventTargetProperties);
|
||||
Object.defineProperties(globalThis, mainRuntimeGlobalProperties);
|
||||
setEventTargetData(globalThis);
|
||||
// Registers the handler for window.onload function.
|
||||
globalThis.addEventListener("load", (e: domTypes.Event): void => {
|
||||
globalThis.addEventListener("load", (e) => {
|
||||
const { onload } = globalThis;
|
||||
if (typeof onload === "function") {
|
||||
onload(e);
|
||||
}
|
||||
});
|
||||
// Registers the handler for window.onunload function.
|
||||
globalThis.addEventListener("unload", (e: domTypes.Event): void => {
|
||||
globalThis.addEventListener("unload", (e) => {
|
||||
const { onunload } = globalThis;
|
||||
if (typeof onunload === "function") {
|
||||
onunload(e);
|
||||
|
|
9
cli/js/tests/dom_exception_test.ts
Normal file
9
cli/js/tests/dom_exception_test.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { unitTest, assertEquals, assert } from "./test_util.ts";
|
||||
|
||||
unitTest(function testDomError() {
|
||||
const de = new DOMException("foo", "bar");
|
||||
assert(de);
|
||||
assertEquals(de.message, "foo");
|
||||
assertEquals(de.name, "bar");
|
||||
});
|
|
@ -35,18 +35,6 @@ unitTest(function constructedEventTargetCanBeUsedAsExpected(): void {
|
|||
assertEquals(callCount, 2);
|
||||
});
|
||||
|
||||
// TODO(ry) Should AddEventListenerOptions and EventListenerOptions be exposed
|
||||
// from the public API?
|
||||
|
||||
interface AddEventListenerOptions extends EventListenerOptions {
|
||||
once?: boolean;
|
||||
passive?: boolean;
|
||||
}
|
||||
|
||||
interface EventListenerOptions {
|
||||
capture?: boolean;
|
||||
}
|
||||
|
||||
unitTest(function anEventTargetCanBeSubclassed(): void {
|
||||
class NicerEventTarget extends EventTarget {
|
||||
on(
|
||||
|
|
|
@ -48,10 +48,8 @@ unitTest(function eventStopImmediatePropagationSuccess(): void {
|
|||
const event = new Event(type);
|
||||
|
||||
assertEquals(event.cancelBubble, false);
|
||||
assertEquals(event.cancelBubbleImmediately, false);
|
||||
event.stopImmediatePropagation();
|
||||
assertEquals(event.cancelBubble, true);
|
||||
assertEquals(event.cancelBubbleImmediately, true);
|
||||
});
|
||||
|
||||
unitTest(function eventPreventDefaultSuccess(): void {
|
||||
|
|
|
@ -16,6 +16,7 @@ import "./custom_event_test.ts";
|
|||
import "./dir_test.ts";
|
||||
import "./dispatch_minimal_test.ts";
|
||||
import "./dispatch_json_test.ts";
|
||||
import "./dom_exception_test.ts";
|
||||
import "./error_stack_test.ts";
|
||||
import "./event_test.ts";
|
||||
import "./event_target_test.ts";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { TextDecoder, TextEncoder } from "./text_encoding.ts";
|
||||
import { build } from "../build.ts";
|
||||
import { ReadableStream } from "./streams/mod.ts";
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as formData from "./form_data.ts";
|
|||
import * as blob from "./blob.ts";
|
||||
import * as encoding from "./text_encoding.ts";
|
||||
import * as headers from "./headers.ts";
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { ReadableStream } from "./streams/mod.ts";
|
||||
|
||||
const { Headers } = headers;
|
||||
|
|
|
@ -1,44 +1,28 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as event from "./event.ts";
|
||||
import { EventImpl as Event } from "./event.ts";
|
||||
import { requiredArguments } from "./util.ts";
|
||||
|
||||
export class CustomEvent extends event.Event implements domTypes.CustomEvent {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
#detail: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class CustomEventImpl<T = any> extends Event implements CustomEvent {
|
||||
#detail: T;
|
||||
|
||||
constructor(
|
||||
type: string,
|
||||
customEventInitDict: domTypes.CustomEventInit = {}
|
||||
) {
|
||||
super(type, customEventInitDict);
|
||||
constructor(type: string, eventInitDict: CustomEventInit<T> = {}) {
|
||||
super(type, eventInitDict);
|
||||
requiredArguments("CustomEvent", arguments.length, 1);
|
||||
const { detail = null } = customEventInitDict;
|
||||
this.#detail = detail;
|
||||
const { detail } = eventInitDict;
|
||||
this.#detail = detail as T;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
get detail(): any {
|
||||
get detail(): T {
|
||||
return this.#detail;
|
||||
}
|
||||
|
||||
initCustomEvent(
|
||||
_type: string,
|
||||
_bubbles?: boolean,
|
||||
_cancelable?: boolean,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
detail?: any
|
||||
): void {
|
||||
if (this.dispatched) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#detail = detail;
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag](): string {
|
||||
return "CustomEvent";
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.defineProperty(CustomEvent.prototype, "detail", { enumerable: true });
|
||||
Reflect.defineProperty(CustomEventImpl.prototype, "detail", {
|
||||
enumerable: true,
|
||||
});
|
||||
|
|
14
cli/js/web/dom_exception.ts
Normal file
14
cli/js/web/dom_exception.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
export class DOMExceptionImpl extends Error implements DOMException {
|
||||
#name: string;
|
||||
|
||||
constructor(message = "", name = "Error") {
|
||||
super(message);
|
||||
this.#name = name;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this.#name;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import * as blob from "./blob.ts";
|
||||
|
||||
export class DomFileImpl extends blob.DenoBlob implements domTypes.DomFile {
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { DomIterable } from "./dom_types.ts";
|
||||
import { requiredArguments } from "./util.ts";
|
||||
import { exposeForTest } from "../internals.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
export type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export interface DomIterable<K, V> {
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<[K, V]>;
|
||||
[Symbol.iterator](): IterableIterator<[K, V]>;
|
||||
forEach(
|
||||
callback: (value: V, key: K, parent: this) => void,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
thisArg?: any
|
||||
): void;
|
||||
}
|
||||
|
||||
export function DomIterableMixin<K, V, TBase extends Constructor>(
|
||||
Base: TBase,
|
||||
|
|
451
cli/js/web/dom_types.ts → cli/js/web/dom_types.d.ts
vendored
451
cli/js/web/dom_types.ts → cli/js/web/dom_types.d.ts
vendored
|
@ -23,7 +23,7 @@ export type HeadersInit =
|
|||
| Headers
|
||||
| Array<[string, string]>
|
||||
| Record<string, string>;
|
||||
export type URLSearchParamsInit = string | string[][] | Record<string, string>;
|
||||
|
||||
type BodyInit =
|
||||
| Blob
|
||||
| BufferSource
|
||||
|
@ -31,7 +31,9 @@ type BodyInit =
|
|||
| URLSearchParams
|
||||
| ReadableStream
|
||||
| string;
|
||||
|
||||
export type RequestInfo = Request | string;
|
||||
|
||||
type ReferrerPolicy =
|
||||
| ""
|
||||
| "no-referrer"
|
||||
|
@ -39,21 +41,12 @@ type ReferrerPolicy =
|
|||
| "origin-only"
|
||||
| "origin-when-cross-origin"
|
||||
| "unsafe-url";
|
||||
|
||||
export type BlobPart = BufferSource | Blob | string;
|
||||
|
||||
export type FormDataEntryValue = DomFile | string;
|
||||
|
||||
export interface DomIterable<K, V> {
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
entries(): IterableIterator<[K, V]>;
|
||||
[Symbol.iterator](): IterableIterator<[K, V]>;
|
||||
forEach(
|
||||
callback: (value: V, key: K, parent: this) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
}
|
||||
|
||||
type EndingType = "transparent" | "native";
|
||||
export type EndingType = "transparent" | "native";
|
||||
|
||||
export interface BlobPropertyBag {
|
||||
type?: string;
|
||||
|
@ -64,67 +57,16 @@ interface AbortSignalEventMap {
|
|||
abort: ProgressEvent;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#node
|
||||
export enum NodeType {
|
||||
ELEMENT_NODE = 1,
|
||||
TEXT_NODE = 3,
|
||||
DOCUMENT_FRAGMENT_NODE = 11,
|
||||
}
|
||||
|
||||
export const eventTargetHost: unique symbol = Symbol();
|
||||
export const eventTargetListeners: unique symbol = Symbol();
|
||||
export const eventTargetMode: 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 {
|
||||
// TODO: below 4 symbol props should not present on EventTarget WebIDL.
|
||||
// They should be implementation specific details.
|
||||
[eventTargetHost]: EventTarget | null;
|
||||
[eventTargetListeners]: { [type in string]: EventTargetListener[] };
|
||||
[eventTargetMode]: string;
|
||||
[eventTargetNodeType]: NodeType;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject | null,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
dispatchEvent(event: Event): boolean;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject | null,
|
||||
options?: EventListenerOptions | boolean
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface ProgressEventInit extends EventInit {
|
||||
lengthComputable?: boolean;
|
||||
loaded?: number;
|
||||
total?: number;
|
||||
}
|
||||
|
||||
export interface URLSearchParams extends DomIterable<string, string> {
|
||||
export class URLSearchParams {
|
||||
constructor(
|
||||
init?: string[][] | Record<string, string> | string | URLSearchParams
|
||||
);
|
||||
append(name: string, value: string): void;
|
||||
delete(name: string): void;
|
||||
get(name: string): string | null;
|
||||
|
@ -137,72 +79,229 @@ export interface URLSearchParams extends DomIterable<string, string> {
|
|||
callbackfn: (value: string, key: string, parent: this) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
keys(): IterableIterator<string>;
|
||||
values(): IterableIterator<string>;
|
||||
static toString(): string;
|
||||
}
|
||||
|
||||
export interface EventInit {
|
||||
bubbles?: boolean;
|
||||
cancelable?: boolean;
|
||||
export interface UIEventInit extends EventInit {
|
||||
detail?: number;
|
||||
// adjust Window -> Node
|
||||
view?: Node | null;
|
||||
}
|
||||
|
||||
export class UIEvent extends Event {
|
||||
constructor(type: string, eventInitDict?: UIEventInit);
|
||||
readonly detail: number;
|
||||
// adjust Window -> Node
|
||||
readonly view: Node | null;
|
||||
}
|
||||
|
||||
export interface FocusEventInit extends UIEventInit {
|
||||
relatedTarget?: EventTarget | null;
|
||||
}
|
||||
|
||||
export class FocusEvent extends UIEvent {
|
||||
constructor(type: string, eventInitDict?: FocusEventInit);
|
||||
readonly relatedTarget: EventTarget | null;
|
||||
}
|
||||
|
||||
export interface EventModifierInit extends UIEventInit {
|
||||
altKey?: boolean;
|
||||
ctrlKey?: boolean;
|
||||
metaKey?: boolean;
|
||||
modifierAltGraph?: boolean;
|
||||
modifierCapsLock?: boolean;
|
||||
modifierFn?: boolean;
|
||||
modifierFnLock?: boolean;
|
||||
modifierHyper?: boolean;
|
||||
modifierNumLock?: boolean;
|
||||
modifierScrollLock?: boolean;
|
||||
modifierSuper?: boolean;
|
||||
modifierSymbol?: boolean;
|
||||
modifierSymbolLock?: boolean;
|
||||
shiftKey?: boolean;
|
||||
}
|
||||
|
||||
export interface MouseEventInit extends EventModifierInit {
|
||||
button?: number;
|
||||
buttons?: number;
|
||||
clientX?: number;
|
||||
clientY?: number;
|
||||
movementX?: number;
|
||||
movementY?: number;
|
||||
relatedTarget?: EventTarget | null;
|
||||
screenX?: number;
|
||||
screenY?: number;
|
||||
}
|
||||
|
||||
export class MouseEvent extends UIEvent {
|
||||
constructor(type: string, eventInitDict?: MouseEventInit);
|
||||
readonly altKey: boolean;
|
||||
readonly button: number;
|
||||
readonly buttons: number;
|
||||
readonly clientX: number;
|
||||
readonly clientY: number;
|
||||
readonly ctrlKey: boolean;
|
||||
readonly metaKey: boolean;
|
||||
readonly movementX: number;
|
||||
readonly movementY: number;
|
||||
readonly offsetX: number;
|
||||
readonly offsetY: number;
|
||||
readonly pageX: number;
|
||||
readonly pageY: number;
|
||||
readonly relatedTarget: EventTarget | null;
|
||||
readonly screenX: number;
|
||||
readonly screenY: number;
|
||||
readonly shiftKey: boolean;
|
||||
readonly x: number;
|
||||
readonly y: number;
|
||||
getModifierState(keyArg: string): boolean;
|
||||
}
|
||||
|
||||
interface GetRootNodeOptions {
|
||||
composed?: boolean;
|
||||
}
|
||||
|
||||
export interface CustomEventInit extends EventInit {
|
||||
detail?: any;
|
||||
export class Node extends EventTarget {
|
||||
readonly baseURI: string;
|
||||
readonly childNodes: NodeListOf<ChildNode>;
|
||||
readonly firstChild: ChildNode | null;
|
||||
readonly isConnected: boolean;
|
||||
readonly lastChild: ChildNode | null;
|
||||
readonly nextSibling: ChildNode | null;
|
||||
readonly nodeName: string;
|
||||
readonly nodeType: number;
|
||||
nodeValue: string | null;
|
||||
// adjusted: Document -> Node
|
||||
readonly ownerDocument: Node | null;
|
||||
// adjusted: HTMLElement -> Node
|
||||
readonly parentElement: Node | null;
|
||||
readonly parentNode: (Node & ParentNode) | null;
|
||||
readonly previousSibling: ChildNode | null;
|
||||
textContent: string | null;
|
||||
appendChild<T extends Node>(newChild: T): T;
|
||||
cloneNode(deep?: boolean): Node;
|
||||
compareDocumentPosition(other: Node): number;
|
||||
contains(other: Node | null): boolean;
|
||||
getRootNode(options?: GetRootNodeOptions): Node;
|
||||
hasChildNodes(): boolean;
|
||||
insertBefore<T extends Node>(newChild: T, refChild: Node | null): T;
|
||||
isDefaultNamespace(namespace: string | null): boolean;
|
||||
isEqualNode(otherNode: Node | null): boolean;
|
||||
isSameNode(otherNode: Node | null): boolean;
|
||||
lookupNamespaceURI(prefix: string | null): string | null;
|
||||
lookupPrefix(namespace: string | null): string | null;
|
||||
normalize(): void;
|
||||
removeChild<T extends Node>(oldChild: T): T;
|
||||
replaceChild<T extends Node>(newChild: Node, oldChild: T): T;
|
||||
readonly ATTRIBUTE_NODE: number;
|
||||
readonly CDATA_SECTION_NODE: number;
|
||||
readonly COMMENT_NODE: number;
|
||||
readonly DOCUMENT_FRAGMENT_NODE: number;
|
||||
readonly DOCUMENT_NODE: number;
|
||||
readonly DOCUMENT_POSITION_CONTAINED_BY: number;
|
||||
readonly DOCUMENT_POSITION_CONTAINS: number;
|
||||
readonly DOCUMENT_POSITION_DISCONNECTED: number;
|
||||
readonly DOCUMENT_POSITION_FOLLOWING: number;
|
||||
readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number;
|
||||
readonly DOCUMENT_POSITION_PRECEDING: number;
|
||||
readonly DOCUMENT_TYPE_NODE: number;
|
||||
readonly ELEMENT_NODE: number;
|
||||
readonly ENTITY_NODE: number;
|
||||
readonly ENTITY_REFERENCE_NODE: number;
|
||||
readonly NOTATION_NODE: number;
|
||||
readonly PROCESSING_INSTRUCTION_NODE: number;
|
||||
readonly TEXT_NODE: number;
|
||||
static readonly ATTRIBUTE_NODE: number;
|
||||
static readonly CDATA_SECTION_NODE: number;
|
||||
static readonly COMMENT_NODE: number;
|
||||
static readonly DOCUMENT_FRAGMENT_NODE: number;
|
||||
static readonly DOCUMENT_NODE: number;
|
||||
static readonly DOCUMENT_POSITION_CONTAINED_BY: number;
|
||||
static readonly DOCUMENT_POSITION_CONTAINS: number;
|
||||
static readonly DOCUMENT_POSITION_DISCONNECTED: number;
|
||||
static readonly DOCUMENT_POSITION_FOLLOWING: number;
|
||||
static readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number;
|
||||
static readonly DOCUMENT_POSITION_PRECEDING: number;
|
||||
static readonly DOCUMENT_TYPE_NODE: number;
|
||||
static readonly ELEMENT_NODE: number;
|
||||
static readonly ENTITY_NODE: number;
|
||||
static readonly ENTITY_REFERENCE_NODE: number;
|
||||
static readonly NOTATION_NODE: number;
|
||||
static readonly PROCESSING_INSTRUCTION_NODE: number;
|
||||
static readonly TEXT_NODE: number;
|
||||
}
|
||||
|
||||
export enum EventPhase {
|
||||
NONE = 0,
|
||||
CAPTURING_PHASE = 1,
|
||||
AT_TARGET = 2,
|
||||
BUBBLING_PHASE = 3,
|
||||
interface Slotable {
|
||||
// adjusted: HTMLSlotElement -> Node
|
||||
readonly assignedSlot: Node | null;
|
||||
}
|
||||
|
||||
export interface EventPath {
|
||||
item: EventTarget;
|
||||
itemInShadowTree: boolean;
|
||||
relatedTarget: EventTarget | null;
|
||||
rootOfClosedTree: boolean;
|
||||
slotInClosedTree: boolean;
|
||||
target: EventTarget | null;
|
||||
touchTargetList: EventTarget[];
|
||||
interface ChildNode extends Node {
|
||||
after(...nodes: Array<Node | string>): void;
|
||||
before(...nodes: Array<Node | string>): void;
|
||||
remove(): void;
|
||||
replaceWith(...nodes: Array<Node | string>): void;
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
readonly type: string;
|
||||
target: EventTarget | null;
|
||||
currentTarget: EventTarget | null;
|
||||
composedPath(): EventPath[];
|
||||
|
||||
eventPhase: number;
|
||||
|
||||
stopPropagation(): void;
|
||||
stopImmediatePropagation(): void;
|
||||
|
||||
readonly bubbles: boolean;
|
||||
readonly cancelable: boolean;
|
||||
preventDefault(): void;
|
||||
readonly defaultPrevented: boolean;
|
||||
readonly composed: boolean;
|
||||
|
||||
isTrusted: boolean;
|
||||
readonly timeStamp: Date;
|
||||
|
||||
dispatched: boolean;
|
||||
readonly initialized: boolean;
|
||||
inPassiveListener: boolean;
|
||||
cancelBubble: boolean;
|
||||
cancelBubbleImmediately: boolean;
|
||||
path: EventPath[];
|
||||
relatedTarget: EventTarget | null;
|
||||
interface ParentNode {
|
||||
readonly childElementCount: number;
|
||||
// not currently supported
|
||||
// readonly children: HTMLCollection;
|
||||
// adjusted: Element -> Node
|
||||
readonly firstElementChild: Node | null;
|
||||
// adjusted: Element -> Node
|
||||
readonly lastElementChild: Node | null;
|
||||
append(...nodes: Array<Node | string>): void;
|
||||
prepend(...nodes: Array<Node | string>): void;
|
||||
// not currently supported
|
||||
// querySelector<K extends keyof HTMLElementTagNameMap>(
|
||||
// selectors: K,
|
||||
// ): HTMLElementTagNameMap[K] | null;
|
||||
// querySelector<K extends keyof SVGElementTagNameMap>(
|
||||
// selectors: K,
|
||||
// ): SVGElementTagNameMap[K] | null;
|
||||
// querySelector<E extends Element = Element>(selectors: string): E | null;
|
||||
// querySelectorAll<K extends keyof HTMLElementTagNameMap>(
|
||||
// selectors: K,
|
||||
// ): NodeListOf<HTMLElementTagNameMap[K]>;
|
||||
// querySelectorAll<K extends keyof SVGElementTagNameMap>(
|
||||
// selectors: K,
|
||||
// ): NodeListOf<SVGElementTagNameMap[K]>;
|
||||
// querySelectorAll<E extends Element = Element>(
|
||||
// selectors: string,
|
||||
// ): NodeListOf<E>;
|
||||
}
|
||||
|
||||
export interface CustomEvent extends Event {
|
||||
readonly detail: any;
|
||||
initCustomEvent(
|
||||
type: string,
|
||||
bubbles?: boolean,
|
||||
cancelable?: boolean,
|
||||
detail?: any | null
|
||||
interface NodeList {
|
||||
readonly length: number;
|
||||
item(index: number): Node | null;
|
||||
forEach(
|
||||
callbackfn: (value: Node, key: number, parent: NodeList) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
[index: number]: Node;
|
||||
[Symbol.iterator](): IterableIterator<Node>;
|
||||
entries(): IterableIterator<[number, Node]>;
|
||||
keys(): IterableIterator<number>;
|
||||
values(): IterableIterator<Node>;
|
||||
}
|
||||
|
||||
interface NodeListOf<TNode extends Node> extends NodeList {
|
||||
length: number;
|
||||
item(index: number): TNode;
|
||||
forEach(
|
||||
callbackfn: (value: TNode, key: number, parent: NodeListOf<TNode>) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
[index: number]: TNode;
|
||||
[Symbol.iterator](): IterableIterator<TNode>;
|
||||
entries(): IterableIterator<[number, TNode]>;
|
||||
keys(): IterableIterator<number>;
|
||||
values(): IterableIterator<TNode>;
|
||||
}
|
||||
|
||||
export interface DomFile extends Blob {
|
||||
|
@ -225,15 +324,6 @@ interface ProgressEvent extends Event {
|
|||
readonly total: number;
|
||||
}
|
||||
|
||||
export interface EventListenerOptions {
|
||||
capture?: boolean;
|
||||
}
|
||||
|
||||
export interface AddEventListenerOptions extends EventListenerOptions {
|
||||
once?: boolean;
|
||||
passive?: boolean;
|
||||
}
|
||||
|
||||
export interface AbortSignal extends EventTarget {
|
||||
readonly aborted: boolean;
|
||||
onabort: ((this: AbortSignal, ev: ProgressEvent) => any) | null;
|
||||
|
@ -259,18 +349,17 @@ export interface AbortSignal extends EventTarget {
|
|||
): void;
|
||||
}
|
||||
|
||||
export interface FormData extends DomIterable<string, FormDataEntryValue> {
|
||||
export class FormData {
|
||||
append(name: string, value: string | Blob, fileName?: string): void;
|
||||
delete(name: string): void;
|
||||
get(name: string): FormDataEntryValue | null;
|
||||
getAll(name: string): FormDataEntryValue[];
|
||||
has(name: string): boolean;
|
||||
set(name: string, value: string | Blob, fileName?: string): void;
|
||||
}
|
||||
|
||||
export interface FormDataConstructor {
|
||||
new (): FormData;
|
||||
prototype: FormData;
|
||||
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
|
||||
entries(): IterableIterator<[string, FormDataEntryValue]>;
|
||||
keys(): IterableIterator<string>;
|
||||
values(): IterableIterator<FormDataEntryValue>;
|
||||
}
|
||||
|
||||
export interface Blob {
|
||||
|
@ -493,6 +582,7 @@ export interface WritableStreamDefaultController {
|
|||
error(error?: any): void;
|
||||
}
|
||||
*/
|
||||
|
||||
export interface QueuingStrategy<T = any> {
|
||||
highWaterMark?: number;
|
||||
size?: QueuingStrategySizeCallback<T>;
|
||||
|
@ -502,25 +592,21 @@ export interface QueuingStrategySizeCallback<T = any> {
|
|||
(chunk: T): number;
|
||||
}
|
||||
|
||||
export interface Headers extends DomIterable<string, string> {
|
||||
export class Headers {
|
||||
constructor(init?: HeadersInit);
|
||||
append(name: string, value: string): void;
|
||||
delete(name: string): void;
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
get(name: string): string | null;
|
||||
has(name: string): boolean;
|
||||
keys(): IterableIterator<string>;
|
||||
set(name: string, value: string): void;
|
||||
values(): IterableIterator<string>;
|
||||
forEach(
|
||||
callbackfn: (value: string, key: string, parent: this) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
}
|
||||
|
||||
export interface HeadersConstructor {
|
||||
new (init?: HeadersInit): Headers;
|
||||
prototype: Headers;
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
keys(): IterableIterator<string>;
|
||||
values(): IterableIterator<string>;
|
||||
}
|
||||
|
||||
type RequestCache =
|
||||
|
@ -582,11 +668,6 @@ export interface ResponseInit {
|
|||
statusText?: string;
|
||||
}
|
||||
|
||||
export interface RequestConstructor {
|
||||
new (input: RequestInfo, init?: RequestInit): Request;
|
||||
prototype: Request;
|
||||
}
|
||||
|
||||
export interface Request extends Body {
|
||||
readonly cache?: RequestCache;
|
||||
readonly credentials?: RequestCredentials;
|
||||
|
@ -606,6 +687,11 @@ export interface Request extends Body {
|
|||
clone(): Request;
|
||||
}
|
||||
|
||||
export interface RequestConstructor {
|
||||
new (input: RequestInfo, init?: RequestInit): Request;
|
||||
prototype: Request;
|
||||
}
|
||||
|
||||
export interface Response extends Body {
|
||||
readonly headers: Headers;
|
||||
readonly ok: boolean;
|
||||
|
@ -618,14 +704,22 @@ export interface Response extends Body {
|
|||
clone(): Response;
|
||||
}
|
||||
|
||||
export interface DOMStringList {
|
||||
export interface ResponseConstructor {
|
||||
prototype: Response;
|
||||
new (body?: BodyInit | null, init?: ResponseInit): Response;
|
||||
error(): Response;
|
||||
redirect(url: string, status?: number): Response;
|
||||
}
|
||||
|
||||
export class DOMStringList {
|
||||
readonly length: number;
|
||||
contains(string: string): boolean;
|
||||
item(index: number): string | null;
|
||||
[index: number]: string;
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
export class Location {
|
||||
readonly ancestorOrigins: DOMStringList;
|
||||
hash: string;
|
||||
host: string;
|
||||
|
@ -642,7 +736,8 @@ export interface Location {
|
|||
replace(url: string): void;
|
||||
}
|
||||
|
||||
export interface URL {
|
||||
export class URL {
|
||||
constructor(url: string, base?: string | URL);
|
||||
hash: string;
|
||||
host: string;
|
||||
hostname: string;
|
||||
|
@ -657,54 +752,6 @@ export interface URL {
|
|||
readonly searchParams: URLSearchParams;
|
||||
username: string;
|
||||
toJSON(): string;
|
||||
}
|
||||
|
||||
export interface URLSearchParams {
|
||||
/**
|
||||
* Appends a specified key/value pair as a new search parameter.
|
||||
*/
|
||||
append(name: string, value: string): void;
|
||||
/**
|
||||
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
|
||||
*/
|
||||
delete(name: string): void;
|
||||
/**
|
||||
* Returns the first value associated to the given search parameter.
|
||||
*/
|
||||
get(name: string): string | null;
|
||||
/**
|
||||
* Returns all the values association with a given search parameter.
|
||||
*/
|
||||
getAll(name: string): string[];
|
||||
/**
|
||||
* Returns a Boolean indicating if such a search parameter exists.
|
||||
*/
|
||||
has(name: string): boolean;
|
||||
/**
|
||||
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
|
||||
*/
|
||||
set(name: string, value: string): void;
|
||||
sort(): void;
|
||||
/**
|
||||
* Returns a string containing a query string suitable for use in a URL. Does not include the question mark.
|
||||
*/
|
||||
toString(): string;
|
||||
forEach(
|
||||
callbackfn: (value: string, key: string, parent: URLSearchParams) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the search params.
|
||||
*/
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns a list of keys in the search params.
|
||||
*/
|
||||
keys(): IterableIterator<string>;
|
||||
/**
|
||||
* Returns a list of values in the search params.
|
||||
*/
|
||||
values(): IterableIterator<string>;
|
||||
static createObjectURL(object: any): string;
|
||||
static revokeObjectURL(url: string): void;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// Utility functions for DOM nodes
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
|
||||
export function getDOMStringList(arr: string[]): domTypes.DOMStringList {
|
||||
Object.defineProperties(arr, {
|
||||
|
@ -16,87 +16,5 @@ export function getDOMStringList(arr: string[]): domTypes.DOMStringList {
|
|||
},
|
||||
},
|
||||
});
|
||||
return (arr as unknown) as domTypes.DOMStringList;
|
||||
}
|
||||
|
||||
export function isNode(nodeImpl: domTypes.EventTarget | null): boolean {
|
||||
return Boolean(nodeImpl && "nodeType" in nodeImpl);
|
||||
}
|
||||
|
||||
export function isShadowRoot(nodeImpl: domTypes.EventTarget | null): boolean {
|
||||
return Boolean(
|
||||
nodeImpl &&
|
||||
nodeImpl[domTypes.eventTargetNodeType] ===
|
||||
domTypes.NodeType.DOCUMENT_FRAGMENT_NODE &&
|
||||
nodeImpl[domTypes.eventTargetHost] != null
|
||||
);
|
||||
}
|
||||
|
||||
export function isSlotable(nodeImpl: domTypes.EventTarget | null): boolean {
|
||||
return Boolean(
|
||||
nodeImpl &&
|
||||
(nodeImpl[domTypes.eventTargetNodeType] ===
|
||||
domTypes.NodeType.ELEMENT_NODE ||
|
||||
nodeImpl[domTypes.eventTargetNodeType] === domTypes.NodeType.TEXT_NODE)
|
||||
);
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#node-trees
|
||||
// const domSymbolTree = Symbol("DOM Symbol Tree");
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
|
||||
export function isShadowInclusiveAncestor(
|
||||
ancestor: domTypes.EventTarget | null,
|
||||
node: domTypes.EventTarget | null
|
||||
): boolean {
|
||||
while (isNode(node)) {
|
||||
if (node === ancestor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isShadowRoot(node)) {
|
||||
node = node && node[domTypes.eventTargetHost];
|
||||
} else {
|
||||
node = null; // domSymbolTree.parent(node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getRoot(
|
||||
node: domTypes.EventTarget | null
|
||||
): domTypes.EventTarget | null {
|
||||
const root = node;
|
||||
|
||||
// for (const ancestor of domSymbolTree.ancestorsIterator(node)) {
|
||||
// root = ancestor;
|
||||
// }
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#retarget
|
||||
export function retarget(
|
||||
a: domTypes.EventTarget | null,
|
||||
b: domTypes.EventTarget
|
||||
): domTypes.EventTarget | null {
|
||||
while (true) {
|
||||
if (!isNode(a)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
const aRoot = getRoot(a);
|
||||
|
||||
if (aRoot) {
|
||||
if (
|
||||
!isShadowRoot(aRoot) ||
|
||||
(isNode(b) && isShadowInclusiveAncestor(aRoot, b))
|
||||
) {
|
||||
return a;
|
||||
}
|
||||
|
||||
a = aRoot[domTypes.eventTargetHost];
|
||||
}
|
||||
}
|
||||
return arr as string[] & domTypes.DOMStringList;
|
||||
}
|
||||
|
|
|
@ -1,45 +1,153 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import { getPrivateValue, requiredArguments } from "./util.ts";
|
||||
|
||||
// WeakMaps are recommended for private attributes (see MDN link below)
|
||||
// https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Add-on_SDK/Guides/Contributor_s_Guide/Private_Properties#Using_WeakMaps
|
||||
export const eventAttributes = new WeakMap();
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { defineEnumerableProps, requiredArguments } from "./util.ts";
|
||||
import { assert } from "../util.ts";
|
||||
|
||||
function isTrusted(this: Event): boolean {
|
||||
return getPrivateValue(this, eventAttributes, "isTrusted");
|
||||
/** Stores a non-accessible view of the event path which is used internally in
|
||||
* the logic for determining the path of an event. */
|
||||
export interface EventPath {
|
||||
item: EventTarget;
|
||||
itemInShadowTree: boolean;
|
||||
relatedTarget: EventTarget | null;
|
||||
rootOfClosedTree: boolean;
|
||||
slotInClosedTree: boolean;
|
||||
target: EventTarget | null;
|
||||
touchTargetList: EventTarget[];
|
||||
}
|
||||
|
||||
export class Event implements domTypes.Event {
|
||||
interface EventAttributes {
|
||||
type: string;
|
||||
bubbles: boolean;
|
||||
cancelable: boolean;
|
||||
composed: boolean;
|
||||
currentTarget: EventTarget | null;
|
||||
eventPhase: number;
|
||||
target: EventTarget | null;
|
||||
timeStamp: number;
|
||||
}
|
||||
|
||||
interface EventData {
|
||||
dispatched: boolean;
|
||||
inPassiveListener: boolean;
|
||||
isTrusted: boolean;
|
||||
path: EventPath[];
|
||||
stopImmediatePropagation: boolean;
|
||||
}
|
||||
|
||||
const eventData = new WeakMap<Event, EventData>();
|
||||
|
||||
// accessors for non runtime visible data
|
||||
|
||||
export function getDispatched(event: Event): boolean {
|
||||
return Boolean(eventData.get(event)?.dispatched);
|
||||
}
|
||||
|
||||
export function getPath(event: Event): EventPath[] {
|
||||
return eventData.get(event)?.path ?? [];
|
||||
}
|
||||
|
||||
export function getStopImmediatePropagation(event: Event): boolean {
|
||||
return Boolean(eventData.get(event)?.stopImmediatePropagation);
|
||||
}
|
||||
|
||||
export function setCurrentTarget(
|
||||
event: Event,
|
||||
value: EventTarget | null
|
||||
): void {
|
||||
(event as EventImpl).currentTarget = value;
|
||||
}
|
||||
|
||||
export function setDispatched(event: Event, value: boolean): void {
|
||||
const data = eventData.get(event as Event);
|
||||
if (data) {
|
||||
data.dispatched = value;
|
||||
}
|
||||
}
|
||||
|
||||
export function setEventPhase(event: Event, value: number): void {
|
||||
(event as EventImpl).eventPhase = value;
|
||||
}
|
||||
|
||||
export function setInPassiveListener(event: Event, value: boolean): void {
|
||||
const data = eventData.get(event as Event);
|
||||
if (data) {
|
||||
data.inPassiveListener = value;
|
||||
}
|
||||
}
|
||||
|
||||
export function setPath(event: Event, value: EventPath[]): void {
|
||||
const data = eventData.get(event as Event);
|
||||
if (data) {
|
||||
data.path = value;
|
||||
}
|
||||
}
|
||||
|
||||
export function setRelatedTarget<T extends Event>(
|
||||
event: T,
|
||||
value: EventTarget | null
|
||||
): void {
|
||||
if ("relatedTarget" in event) {
|
||||
(event as T & {
|
||||
relatedTarget: EventTarget | null;
|
||||
}).relatedTarget = value;
|
||||
}
|
||||
}
|
||||
|
||||
export function setTarget(event: Event, value: EventTarget | null): void {
|
||||
(event as EventImpl).target = value;
|
||||
}
|
||||
|
||||
export function setStopImmediatePropagation(
|
||||
event: Event,
|
||||
value: boolean
|
||||
): void {
|
||||
const data = eventData.get(event as Event);
|
||||
if (data) {
|
||||
data.stopImmediatePropagation = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Type guards that widen the event type
|
||||
|
||||
export function hasRelatedTarget(
|
||||
event: Event
|
||||
): event is domTypes.FocusEvent | domTypes.MouseEvent {
|
||||
return "relatedTarget" in event;
|
||||
}
|
||||
|
||||
function isTrusted(this: Event): boolean {
|
||||
return eventData.get(this)!.isTrusted;
|
||||
}
|
||||
|
||||
export class EventImpl implements Event {
|
||||
// The default value is `false`.
|
||||
// Use `defineProperty` to define on each instance, NOT on the prototype.
|
||||
isTrusted!: boolean;
|
||||
// Each event has the following associated flags
|
||||
private _canceledFlag = false;
|
||||
private _dispatchedFlag = false;
|
||||
private _initializedFlag = false;
|
||||
private _inPassiveListenerFlag = false;
|
||||
private _stopImmediatePropagationFlag = false;
|
||||
private _stopPropagationFlag = false;
|
||||
|
||||
// Property for objects on which listeners will be invoked
|
||||
private _path: domTypes.EventPath[] = [];
|
||||
#canceledFlag = false;
|
||||
#stopPropagationFlag = false;
|
||||
#attributes: EventAttributes;
|
||||
|
||||
constructor(type: string, eventInitDict: domTypes.EventInit = {}) {
|
||||
constructor(type: string, eventInitDict: EventInit = {}) {
|
||||
requiredArguments("Event", arguments.length, 1);
|
||||
type = String(type);
|
||||
this._initializedFlag = true;
|
||||
eventAttributes.set(this, {
|
||||
this.#attributes = {
|
||||
type,
|
||||
bubbles: eventInitDict.bubbles || false,
|
||||
cancelable: eventInitDict.cancelable || false,
|
||||
composed: eventInitDict.composed || false,
|
||||
bubbles: eventInitDict.bubbles ?? false,
|
||||
cancelable: eventInitDict.cancelable ?? false,
|
||||
composed: eventInitDict.composed ?? false,
|
||||
currentTarget: null,
|
||||
eventPhase: domTypes.EventPhase.NONE,
|
||||
isTrusted: false,
|
||||
relatedTarget: null,
|
||||
eventPhase: Event.NONE,
|
||||
target: null,
|
||||
timeStamp: Date.now(),
|
||||
};
|
||||
eventData.set(this, {
|
||||
dispatched: false,
|
||||
inPassiveListener: false,
|
||||
isTrusted: false,
|
||||
path: [],
|
||||
stopImmediatePropagation: false,
|
||||
});
|
||||
Reflect.defineProperty(this, "isTrusted", {
|
||||
enumerable: true,
|
||||
|
@ -48,151 +156,100 @@ export class Event implements domTypes.Event {
|
|||
}
|
||||
|
||||
get bubbles(): boolean {
|
||||
return getPrivateValue(this, eventAttributes, "bubbles");
|
||||
return this.#attributes.bubbles;
|
||||
}
|
||||
|
||||
get cancelBubble(): boolean {
|
||||
return this._stopPropagationFlag;
|
||||
return this.#stopPropagationFlag;
|
||||
}
|
||||
|
||||
set cancelBubble(value: boolean) {
|
||||
this._stopPropagationFlag = value;
|
||||
}
|
||||
|
||||
get cancelBubbleImmediately(): boolean {
|
||||
return this._stopImmediatePropagationFlag;
|
||||
}
|
||||
|
||||
set cancelBubbleImmediately(value: boolean) {
|
||||
this._stopImmediatePropagationFlag = value;
|
||||
this.#stopPropagationFlag = value;
|
||||
}
|
||||
|
||||
get cancelable(): boolean {
|
||||
return getPrivateValue(this, eventAttributes, "cancelable");
|
||||
return this.#attributes.cancelable;
|
||||
}
|
||||
|
||||
get composed(): boolean {
|
||||
return getPrivateValue(this, eventAttributes, "composed");
|
||||
return this.#attributes.composed;
|
||||
}
|
||||
|
||||
get currentTarget(): domTypes.EventTarget {
|
||||
return getPrivateValue(this, eventAttributes, "currentTarget");
|
||||
get currentTarget(): EventTarget | null {
|
||||
return this.#attributes.currentTarget;
|
||||
}
|
||||
|
||||
set currentTarget(value: domTypes.EventTarget) {
|
||||
eventAttributes.set(this, {
|
||||
set currentTarget(value: EventTarget | null) {
|
||||
this.#attributes = {
|
||||
type: this.type,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
currentTarget: value,
|
||||
eventPhase: this.eventPhase,
|
||||
isTrusted: this.isTrusted,
|
||||
relatedTarget: this.relatedTarget,
|
||||
target: this.target,
|
||||
timeStamp: this.timeStamp,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
get defaultPrevented(): boolean {
|
||||
return this._canceledFlag;
|
||||
}
|
||||
|
||||
get dispatched(): boolean {
|
||||
return this._dispatchedFlag;
|
||||
}
|
||||
|
||||
set dispatched(value: boolean) {
|
||||
this._dispatchedFlag = value;
|
||||
return this.#canceledFlag;
|
||||
}
|
||||
|
||||
get eventPhase(): number {
|
||||
return getPrivateValue(this, eventAttributes, "eventPhase");
|
||||
return this.#attributes.eventPhase;
|
||||
}
|
||||
|
||||
set eventPhase(value: number) {
|
||||
eventAttributes.set(this, {
|
||||
this.#attributes = {
|
||||
type: this.type,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
currentTarget: this.currentTarget,
|
||||
eventPhase: value,
|
||||
isTrusted: this.isTrusted,
|
||||
relatedTarget: this.relatedTarget,
|
||||
target: this.target,
|
||||
timeStamp: this.timeStamp,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
get initialized(): boolean {
|
||||
return this._initializedFlag;
|
||||
return true;
|
||||
}
|
||||
|
||||
set inPassiveListener(value: boolean) {
|
||||
this._inPassiveListenerFlag = value;
|
||||
get target(): EventTarget | null {
|
||||
return this.#attributes.target;
|
||||
}
|
||||
|
||||
get path(): domTypes.EventPath[] {
|
||||
return this._path;
|
||||
}
|
||||
|
||||
set path(value: domTypes.EventPath[]) {
|
||||
this._path = value;
|
||||
}
|
||||
|
||||
get relatedTarget(): domTypes.EventTarget {
|
||||
return getPrivateValue(this, eventAttributes, "relatedTarget");
|
||||
}
|
||||
|
||||
set relatedTarget(value: domTypes.EventTarget) {
|
||||
eventAttributes.set(this, {
|
||||
set target(value: EventTarget | null) {
|
||||
this.#attributes = {
|
||||
type: this.type,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
currentTarget: this.currentTarget,
|
||||
eventPhase: this.eventPhase,
|
||||
isTrusted: this.isTrusted,
|
||||
relatedTarget: value,
|
||||
target: this.target,
|
||||
timeStamp: this.timeStamp,
|
||||
});
|
||||
}
|
||||
|
||||
get target(): domTypes.EventTarget {
|
||||
return getPrivateValue(this, eventAttributes, "target");
|
||||
}
|
||||
|
||||
set target(value: domTypes.EventTarget) {
|
||||
eventAttributes.set(this, {
|
||||
type: this.type,
|
||||
bubbles: this.bubbles,
|
||||
cancelable: this.cancelable,
|
||||
composed: this.composed,
|
||||
currentTarget: this.currentTarget,
|
||||
eventPhase: this.eventPhase,
|
||||
isTrusted: this.isTrusted,
|
||||
relatedTarget: this.relatedTarget,
|
||||
target: value,
|
||||
timeStamp: this.timeStamp,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
get timeStamp(): Date {
|
||||
return getPrivateValue(this, eventAttributes, "timeStamp");
|
||||
get timeStamp(): number {
|
||||
return this.#attributes.timeStamp;
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
return getPrivateValue(this, eventAttributes, "type");
|
||||
return this.#attributes.type;
|
||||
}
|
||||
|
||||
composedPath(): domTypes.EventPath[] {
|
||||
if (this._path.length === 0) {
|
||||
composedPath(): EventTarget[] {
|
||||
const path = eventData.get(this)!.path;
|
||||
if (path.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const composedPath: domTypes.EventPath[] = [
|
||||
assert(this.currentTarget);
|
||||
const composedPath: EventPath[] = [
|
||||
{
|
||||
item: this.currentTarget,
|
||||
itemInShadowTree: false,
|
||||
|
@ -207,8 +264,8 @@ export class Event implements domTypes.Event {
|
|||
let currentTargetIndex = 0;
|
||||
let currentTargetHiddenSubtreeLevel = 0;
|
||||
|
||||
for (let index = this._path.length - 1; index >= 0; index--) {
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = this._path[index];
|
||||
for (let index = path.length - 1; index >= 0; index--) {
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = path[index];
|
||||
|
||||
if (rootOfClosedTree) {
|
||||
currentTargetHiddenSubtreeLevel++;
|
||||
|
@ -228,7 +285,7 @@ export class Event implements domTypes.Event {
|
|||
let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
|
||||
|
||||
for (let i = currentTargetIndex - 1; i >= 0; i--) {
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = this._path[i];
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = path[i];
|
||||
|
||||
if (rootOfClosedTree) {
|
||||
currentHiddenLevel++;
|
||||
|
@ -258,12 +315,8 @@ export class Event implements domTypes.Event {
|
|||
currentHiddenLevel = currentTargetHiddenSubtreeLevel;
|
||||
maxHiddenLevel = currentTargetHiddenSubtreeLevel;
|
||||
|
||||
for (
|
||||
let index = currentTargetIndex + 1;
|
||||
index < this._path.length;
|
||||
index++
|
||||
) {
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = this._path[index];
|
||||
for (let index = currentTargetIndex + 1; index < path.length; index++) {
|
||||
const { item, rootOfClosedTree, slotInClosedTree } = path[index];
|
||||
|
||||
if (slotInClosedTree) {
|
||||
currentHiddenLevel++;
|
||||
|
@ -289,35 +342,65 @@ export class Event implements domTypes.Event {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return composedPath;
|
||||
return composedPath.map((p) => p.item);
|
||||
}
|
||||
|
||||
preventDefault(): void {
|
||||
if (this.cancelable && !this._inPassiveListenerFlag) {
|
||||
this._canceledFlag = true;
|
||||
if (this.cancelable && !eventData.get(this)!.inPassiveListener) {
|
||||
this.#canceledFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
stopPropagation(): void {
|
||||
this._stopPropagationFlag = true;
|
||||
this.#stopPropagationFlag = true;
|
||||
}
|
||||
|
||||
stopImmediatePropagation(): void {
|
||||
this._stopPropagationFlag = true;
|
||||
this._stopImmediatePropagationFlag = true;
|
||||
this.#stopPropagationFlag = true;
|
||||
eventData.get(this)!.stopImmediatePropagation = true;
|
||||
}
|
||||
|
||||
get NONE(): number {
|
||||
return Event.NONE;
|
||||
}
|
||||
|
||||
get CAPTURING_PHASE(): number {
|
||||
return Event.CAPTURING_PHASE;
|
||||
}
|
||||
|
||||
get AT_TARGET(): number {
|
||||
return Event.AT_TARGET;
|
||||
}
|
||||
|
||||
get BUBBLING_PHASE(): number {
|
||||
return Event.BUBBLING_PHASE;
|
||||
}
|
||||
|
||||
static get NONE(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static get CAPTURING_PHASE(): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static get AT_TARGET(): number {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static get BUBBLING_PHASE(): number {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.defineProperty(Event.prototype, "bubbles", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "cancelable", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "composed", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "currentTarget", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "defaultPrevented", {
|
||||
enumerable: true,
|
||||
});
|
||||
Reflect.defineProperty(Event.prototype, "dispatched", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "eventPhase", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "target", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "timeStamp", { enumerable: true });
|
||||
Reflect.defineProperty(Event.prototype, "type", { enumerable: true });
|
||||
defineEnumerableProps(EventImpl, [
|
||||
"bubbles",
|
||||
"cancelable",
|
||||
"composed",
|
||||
"currentTarget",
|
||||
"defaultPrevented",
|
||||
"eventPhase",
|
||||
"target",
|
||||
"timeStamp",
|
||||
"type",
|
||||
]);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, createResolvable, notImplemented } from "../util.ts";
|
||||
import { isTypedArray } from "./util.ts";
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { TextDecoder, TextEncoder } from "./text_encoding.ts";
|
||||
import { DenoBlob, bytesSymbol as blobBytesSymbol } from "./blob.ts";
|
||||
import { Headers } from "./headers.ts";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import * as blob from "./blob.ts";
|
||||
import * as domFile from "./dom_file.ts";
|
||||
import { DomIterableMixin } from "./dom_iterable.ts";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { DomIterableMixin } from "./dom_iterable.ts";
|
||||
import { requiredArguments } from "./util.ts";
|
||||
import { customInspect } from "./console.ts";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { URL } from "./url.ts";
|
||||
import { notImplemented } from "../util.ts";
|
||||
import { DOMStringList, Location } from "./dom_types.ts";
|
||||
import { DOMStringList, Location } from "./dom_types.d.ts";
|
||||
import { getDOMStringList } from "./dom_util.ts";
|
||||
|
||||
export class LocationImpl implements Location {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as headers from "./headers.ts";
|
||||
import * as body from "./body.ts";
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import * as streams from "./streams/mod.ts";
|
||||
|
||||
const { Headers } = headers;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
// import { ReadableStreamDefaultReader } from "./readable-stream-default-reader.ts";
|
||||
// import { WritableStreamDefaultWriter } from "./writable-stream-default-writer.ts";
|
||||
// import { PipeOptions } from "../dom_types.ts";
|
||||
// import { PipeOptions } from "../dom_types.d.ts";
|
||||
// import { Err } from "../errors.ts";
|
||||
|
||||
// // add a wrapper to handle falsy rejections
|
||||
|
|
|
@ -9,7 +9,7 @@ import * as q from "./queue-mixin.ts";
|
|||
import * as shared from "./shared-internals.ts";
|
||||
import { ReadableStreamBYOBRequest } from "./readable-stream-byob-request.ts";
|
||||
import { Queue } from "./queue.ts";
|
||||
import { UnderlyingByteSource } from "../dom_types.ts";
|
||||
import { UnderlyingByteSource } from "../dom_types.d.ts";
|
||||
|
||||
export class ReadableByteStreamController
|
||||
implements rs.SDReadableByteStreamController {
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
QueuingStrategySizeCallback,
|
||||
UnderlyingSource,
|
||||
UnderlyingByteSource,
|
||||
} from "../dom_types.ts";
|
||||
} from "../dom_types.d.ts";
|
||||
|
||||
// ReadableStreamDefaultController
|
||||
export const controlledReadableStream_ = Symbol("controlledReadableStream_");
|
||||
|
|
|
@ -8,7 +8,10 @@ import * as rs from "./readable-internals.ts";
|
|||
import * as shared from "./shared-internals.ts";
|
||||
import * as q from "./queue-mixin.ts";
|
||||
import { Queue } from "./queue.ts";
|
||||
import { QueuingStrategySizeCallback, UnderlyingSource } from "../dom_types.ts";
|
||||
import {
|
||||
QueuingStrategySizeCallback,
|
||||
UnderlyingSource,
|
||||
} from "../dom_types.d.ts";
|
||||
|
||||
export class ReadableStreamDefaultController<OutputType>
|
||||
implements rs.SDReadableStreamDefaultController<OutputType> {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
QueuingStrategySizeCallback,
|
||||
UnderlyingSource,
|
||||
UnderlyingByteSource,
|
||||
} from "../dom_types.ts";
|
||||
} from "../dom_types.d.ts";
|
||||
|
||||
import {
|
||||
ReadableStreamDefaultController,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// TODO don't disable this warning
|
||||
|
||||
import { AbortSignal, QueuingStrategySizeCallback } from "../dom_types.ts";
|
||||
import { AbortSignal, QueuingStrategySizeCallback } from "../dom_types.d.ts";
|
||||
|
||||
// common stream fields
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// TODO reenable this lint here
|
||||
|
||||
import { QueuingStrategy } from "../dom_types.ts";
|
||||
import { QueuingStrategy } from "../dom_types.d.ts";
|
||||
|
||||
export class ByteLengthQueuingStrategy
|
||||
implements QueuingStrategy<ArrayBufferView> {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// import { createReadableStream } from "./readable-stream.ts";
|
||||
// import { createWritableStream } from "./writable-stream.ts";
|
||||
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.ts";
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.d.ts";
|
||||
|
||||
// export const state_ = Symbol("transformState_");
|
||||
// export const backpressure_ = Symbol("backpressure_");
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// import * as ts from "./transform-internals.ts";
|
||||
// import * as shared from "./shared-internals.ts";
|
||||
// import { TransformStreamDefaultController } from "./transform-stream-default-controller.ts";
|
||||
// import { QueuingStrategy } from "../dom_types.ts";
|
||||
// import { QueuingStrategy } from "../dom_types.d.ts";
|
||||
|
||||
// export class TransformStream<InputType, OutputType> {
|
||||
// [ts.backpressure_]: boolean | undefined; // Whether there was backpressure on [[readable]] the last time it was observed
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// import * as shared from "./shared-internals.ts";
|
||||
// import * as q from "./queue-mixin.ts";
|
||||
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.ts";
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.d.ts";
|
||||
|
||||
// export const backpressure_ = Symbol("backpressure_");
|
||||
// export const closeRequest_ = Symbol("closeRequest_");
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// import * as shared from "./shared-internals.ts";
|
||||
// import * as q from "./queue-mixin.ts";
|
||||
// import { Queue } from "./queue.ts";
|
||||
// import { QueuingStrategySizeCallback } from "../dom_types.ts";
|
||||
// import { QueuingStrategySizeCallback } from "../dom_types.d.ts";
|
||||
|
||||
// export class WritableStreamDefaultController<InputType>
|
||||
// implements ws.WritableStreamDefaultController<InputType> {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// setUpWritableStreamDefaultControllerFromUnderlyingSink
|
||||
// } from "./writable-stream-default-controller.ts";
|
||||
// import { WritableStreamDefaultWriter } from "./writable-stream-default-writer.ts";
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.ts";
|
||||
// import { QueuingStrategy, QueuingStrategySizeCallback } from "../dom_types.d.ts";
|
||||
|
||||
// export class WritableStream<InputType> {
|
||||
// [shared.state_]: ws.WritableStreamState;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
import * as base64 from "./base64.ts";
|
||||
import { decodeUtf8 } from "./decode_utf8.ts";
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { core } from "../core.ts";
|
||||
|
||||
const CONTINUE = null;
|
||||
|
@ -348,7 +348,7 @@ encodingIndexes.set("windows-1252", [
|
|||
252,
|
||||
253,
|
||||
254,
|
||||
255
|
||||
255,
|
||||
]);
|
||||
for (const [key, index] of encodingIndexes) {
|
||||
decoders.set(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { customInspect } from "./console.ts";
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { urls, URLSearchParams } from "./url_search_params.ts";
|
||||
import { getRandomValues } from "../ops/get_random_values.ts";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types.ts";
|
||||
import * as domTypes from "./dom_types.d.ts";
|
||||
import { URL, parts } from "./url.ts";
|
||||
import { isIterable, requiredArguments } from "./util.ts";
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ export type TypedArray =
|
|||
| Float32Array
|
||||
| Float64Array;
|
||||
|
||||
// @internal
|
||||
export function isTypedArray(x: unknown): x is TypedArray {
|
||||
return (
|
||||
x instanceof Int8Array ||
|
||||
|
@ -54,19 +55,8 @@ export function immutableDefine(
|
|||
});
|
||||
}
|
||||
|
||||
// Returns values from a WeakMap to emulate private properties in JavaScript
|
||||
export function getPrivateValue<
|
||||
K extends object,
|
||||
V extends object,
|
||||
W extends keyof V
|
||||
>(instance: K, weakMap: WeakMap<K, V>, key: W): V[W] {
|
||||
if (weakMap.has(instance)) {
|
||||
return weakMap.get(instance)![key];
|
||||
}
|
||||
throw new TypeError("Illegal invocation");
|
||||
}
|
||||
|
||||
export function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean {
|
||||
// @internal
|
||||
export function hasOwnProperty(obj: unknown, v: PropertyKey): boolean {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -87,3 +77,19 @@ export function isIterable<T, P extends keyof T, K extends T[P]>(
|
|||
typeof ((o as unknown) as Iterable<[P, K]>)[Symbol.iterator] === "function"
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
interface GenericConstructor<T = any> {
|
||||
prototype: T;
|
||||
}
|
||||
|
||||
/** A helper function which ensures accessors are enumerable, as they normally
|
||||
* are not. */
|
||||
export function defineEnumerableProps(
|
||||
Ctor: GenericConstructor,
|
||||
props: string[]
|
||||
): void {
|
||||
for (const prop of props) {
|
||||
Reflect.defineProperty(Ctor.prototype, prop, { enumerable: true });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import { TextDecoder, TextEncoder } from "./text_encoding.ts";
|
|||
/*
|
||||
import { blobURLMap } from "./web/url.ts";
|
||||
*/
|
||||
import { Event } from "./event.ts";
|
||||
import { EventTarget } from "./event_target.ts";
|
||||
import { EventImpl as Event } from "./event.ts";
|
||||
import { EventTargetImpl as EventTarget } from "./event_target.ts";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
|
|
Loading…
Reference in a new issue