deno.land / x / deno@v1.28.2 / ext / web / 02_event.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module follows most of the WHATWG Living Standard for the DOM logic.// Many parts of the DOM are not implemented in Deno, but the logic for those// parts still exists. This means you will observe a lot of strange structures// and impossible logic branches based on what Deno currently supports."use strict";
((window) => { const core = window.Deno.core; const ops = core.ops; const webidl = window.__bootstrap.webidl; const { DOMException } = window.__bootstrap.domException; const consoleInternal = window.__bootstrap.console; const { ArrayPrototypeFilter, ArrayPrototypeIncludes, ArrayPrototypeIndexOf, ArrayPrototypeMap, ArrayPrototypePush, ArrayPrototypeSlice, ArrayPrototypeSplice, ArrayPrototypeUnshift, Boolean, DateNow, Error, FunctionPrototypeCall, Map, MapPrototypeGet, MapPrototypeSet, ObjectCreate, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, ObjectPrototypeIsPrototypeOf, ReflectDefineProperty, ReflectHas, SafeArrayIterator, StringPrototypeStartsWith, Symbol, SymbolFor, SymbolToStringTag, TypeError, } = window.__bootstrap.primordials;
// accessors for non runtime visible data
function getDispatched(event) { return Boolean(event[_dispatched]); }
function getPath(event) { return event[_path] ?? []; }
function getStopImmediatePropagation(event) { return Boolean(event[_stopImmediatePropagationFlag]); }
function setCurrentTarget( event, value, ) { event[_attributes].currentTarget = value; }
function setIsTrusted(event, value) { event[_isTrusted] = value; }
function setDispatched(event, value) { event[_dispatched] = value; }
function setEventPhase(event, value) { event[_attributes].eventPhase = value; }
function setInPassiveListener(event, value) { event[_inPassiveListener] = value; }
function setPath(event, value) { event[_path] = value; }
function setRelatedTarget( event, value, ) { event[_attributes].relatedTarget = value; }
function setTarget(event, value) { event[_attributes].target = value; }
function setStopImmediatePropagation( event, value, ) { event[_stopImmediatePropagationFlag] = value; }
// Type guards that widen the event type
function hasRelatedTarget( event, ) { return ReflectHas(event, "relatedTarget"); }
const isTrusted = ObjectGetOwnPropertyDescriptor({ get isTrusted() { return this[_isTrusted]; }, }, "isTrusted").get;
const eventInitConverter = webidl.createDictionaryConverter("EventInit", [{ key: "bubbles", defaultValue: false, converter: webidl.converters.boolean, }, { key: "cancelable", defaultValue: false, converter: webidl.converters.boolean, }, { key: "composed", defaultValue: false, converter: webidl.converters.boolean, }]);
const _attributes = Symbol("[[attributes]]"); const _canceledFlag = Symbol("[[canceledFlag]]"); const _stopPropagationFlag = Symbol("[[stopPropagationFlag]]"); const _stopImmediatePropagationFlag = Symbol( "[[stopImmediatePropagationFlag]]", ); const _inPassiveListener = Symbol("[[inPassiveListener]]"); const _dispatched = Symbol("[[dispatched]]"); const _isTrusted = Symbol("[[isTrusted]]"); const _path = Symbol("[[path]]");
class Event { constructor(type, eventInitDict = {}) { // TODO(lucacasonato): remove when this interface is spec aligned this[SymbolToStringTag] = "Event"; this[_canceledFlag] = false; this[_stopPropagationFlag] = false; this[_stopImmediatePropagationFlag] = false; this[_inPassiveListener] = false; this[_dispatched] = false; this[_isTrusted] = false; this[_path] = [];
webidl.requiredArguments(arguments.length, 1, { prefix: "Failed to construct 'Event'", }); type = webidl.converters.DOMString(type, { prefix: "Failed to construct 'Event'", context: "Argument 1", }); const eventInit = eventInitConverter(eventInitDict, { prefix: "Failed to construct 'Event'", context: "Argument 2", }); this[_attributes] = { type, ...eventInit, currentTarget: null, eventPhase: Event.NONE, target: null, timeStamp: DateNow(), }; ReflectDefineProperty(this, "isTrusted", { enumerable: true, get: isTrusted, }); }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(Event.prototype, this), keys: EVENT_PROPS, })); }
get type() { return this[_attributes].type; }
get target() { return this[_attributes].target; }
get srcElement() { return null; }
set srcElement(_) { // this member is deprecated }
get currentTarget() { return this[_attributes].currentTarget; }
composedPath() { const path = this[_path]; if (path.length === 0) { return []; }
if (!this.currentTarget) { throw new Error("assertion error"); } const composedPath = [ { item: this.currentTarget, itemInShadowTree: false, relatedTarget: null, rootOfClosedTree: false, slotInClosedTree: false, target: null, touchTargetList: [], }, ];
let currentTargetIndex = 0; let currentTargetHiddenSubtreeLevel = 0;
for (let index = path.length - 1; index >= 0; index--) { const { item, rootOfClosedTree, slotInClosedTree } = path[index];
if (rootOfClosedTree) { currentTargetHiddenSubtreeLevel++; }
if (item === this.currentTarget) { currentTargetIndex = index; break; }
if (slotInClosedTree) { currentTargetHiddenSubtreeLevel--; } }
let currentHiddenLevel = currentTargetHiddenSubtreeLevel; let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
for (let i = currentTargetIndex - 1; i >= 0; i--) { const { item, rootOfClosedTree, slotInClosedTree } = path[i];
if (rootOfClosedTree) { currentHiddenLevel++; }
if (currentHiddenLevel <= maxHiddenLevel) { ArrayPrototypeUnshift(composedPath, { item, itemInShadowTree: false, relatedTarget: null, rootOfClosedTree: false, slotInClosedTree: false, target: null, touchTargetList: [], }); }
if (slotInClosedTree) { currentHiddenLevel--;
if (currentHiddenLevel < maxHiddenLevel) { maxHiddenLevel = currentHiddenLevel; } } }
currentHiddenLevel = currentTargetHiddenSubtreeLevel; maxHiddenLevel = currentTargetHiddenSubtreeLevel;
for (let index = currentTargetIndex + 1; index < path.length; index++) { const { item, rootOfClosedTree, slotInClosedTree } = path[index];
if (slotInClosedTree) { currentHiddenLevel++; }
if (currentHiddenLevel <= maxHiddenLevel) { ArrayPrototypePush(composedPath, { item, itemInShadowTree: false, relatedTarget: null, rootOfClosedTree: false, slotInClosedTree: false, target: null, touchTargetList: [], }); }
if (rootOfClosedTree) { currentHiddenLevel--;
if (currentHiddenLevel < maxHiddenLevel) { maxHiddenLevel = currentHiddenLevel; } } } return ArrayPrototypeMap(composedPath, (p) => p.item); }
get NONE() { return Event.NONE; }
get CAPTURING_PHASE() { return Event.CAPTURING_PHASE; }
get AT_TARGET() { return Event.AT_TARGET; }
get BUBBLING_PHASE() { return Event.BUBBLING_PHASE; }
static get NONE() { return 0; }
static get CAPTURING_PHASE() { return 1; }
static get AT_TARGET() { return 2; }
static get BUBBLING_PHASE() { return 3; }
get eventPhase() { return this[_attributes].eventPhase; }
stopPropagation() { this[_stopPropagationFlag] = true; }
get cancelBubble() { return this[_stopPropagationFlag]; }
set cancelBubble(value) { this[_stopPropagationFlag] = webidl.converters.boolean(value); }
stopImmediatePropagation() { this[_stopPropagationFlag] = true; this[_stopImmediatePropagationFlag] = true; }
get bubbles() { return this[_attributes].bubbles; }
get cancelable() { return this[_attributes].cancelable; }
get returnValue() { return !this[_canceledFlag]; }
set returnValue(value) { if (!webidl.converters.boolean(value)) { this[_canceledFlag] = true; } }
preventDefault() { if (this[_attributes].cancelable && !this[_inPassiveListener]) { this[_canceledFlag] = true; } }
get defaultPrevented() { return this[_canceledFlag]; }
get composed() { return this[_attributes].composed; }
get initialized() { return true; }
get timeStamp() { return this[_attributes].timeStamp; } }
function defineEnumerableProps( Ctor, props, ) { for (const prop of props) { ReflectDefineProperty(Ctor.prototype, prop, { enumerable: true }); } }
const EVENT_PROPS = [ "bubbles", "cancelable", "composed", "currentTarget", "defaultPrevented", "eventPhase", "srcElement", "target", "returnValue", "timeStamp", "type", ];
defineEnumerableProps(Event, EVENT_PROPS);
// This is currently the only node type we are using, so instead of implementing // the whole of the Node interface at the moment, this just gives us the one // value to power the standards based logic const DOCUMENT_FRAGMENT_NODE = 11;
// DOM Logic Helper functions and type guards
/** Get the parent node, for event targets that have a parent. * * Ref: https://dom.spec.whatwg.org/#get-the-parent */ function getParent(eventTarget) { return isNode(eventTarget) ? eventTarget.parentNode : null; }
function getRoot(eventTarget) { return isNode(eventTarget) ? eventTarget.getRootNode({ composed: true }) : null; }
function isNode( eventTarget, ) { return Boolean(eventTarget && ReflectHas(eventTarget, "nodeType")); }
// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor function isShadowInclusiveAncestor( ancestor, node, ) { while (isNode(node)) { if (node === ancestor) { return true; }
if (isShadowRoot(node)) { node = node && getHost(node); } else { node = getParent(node); } }
return false; }
function isShadowRoot(nodeImpl) { return Boolean( nodeImpl && isNode(nodeImpl) && nodeImpl.nodeType === DOCUMENT_FRAGMENT_NODE && getHost(nodeImpl) != null, ); }
function isSlotable( nodeImpl, ) { return Boolean(isNode(nodeImpl) && ReflectHas(nodeImpl, "assignedSlot")); }
// DOM Logic functions
/** Append a path item to an event's path. * * Ref: https://dom.spec.whatwg.org/#concept-event-path-append */ function appendToEventPath( eventImpl, target, targetOverride, relatedTarget, touchTargets, slotInClosedTree, ) { const itemInShadowTree = isNode(target) && isShadowRoot(getRoot(target)); const rootOfClosedTree = isShadowRoot(target) && getMode(target) === "closed";
ArrayPrototypePush(getPath(eventImpl), { item: target, itemInShadowTree, target: targetOverride, relatedTarget, touchTargetList: touchTargets, rootOfClosedTree, slotInClosedTree, }); }
function dispatch( targetImpl, eventImpl, targetOverride, ) { let clearTargets = false; let activationTarget = null;
setDispatched(eventImpl, true);
targetOverride = targetOverride ?? targetImpl; const eventRelatedTarget = hasRelatedTarget(eventImpl) ? eventImpl.relatedTarget : null; let relatedTarget = retarget(eventRelatedTarget, targetImpl);
if (targetImpl !== relatedTarget || targetImpl === eventRelatedTarget) { const touchTargets = [];
appendToEventPath( eventImpl, targetImpl, targetOverride, relatedTarget, touchTargets, false, );
const isActivationEvent = eventImpl.type === "click";
if (isActivationEvent && getHasActivationBehavior(targetImpl)) { activationTarget = targetImpl; }
let slotInClosedTree = false; let slotable = isSlotable(targetImpl) && getAssignedSlot(targetImpl) ? targetImpl : null; let parent = getParent(targetImpl);
// Populate event path // https://dom.spec.whatwg.org/#event-path while (parent !== null) { if (slotable !== null) { slotable = null;
const parentRoot = getRoot(parent); if ( isShadowRoot(parentRoot) && parentRoot && getMode(parentRoot) === "closed" ) { slotInClosedTree = true; } }
relatedTarget = retarget(eventRelatedTarget, parent);
if ( isNode(parent) && isShadowInclusiveAncestor(getRoot(targetImpl), parent) ) { appendToEventPath( eventImpl, parent, null, relatedTarget, touchTargets, slotInClosedTree, ); } else if (parent === relatedTarget) { parent = null; } else { targetImpl = parent;
if ( isActivationEvent && activationTarget === null && getHasActivationBehavior(targetImpl) ) { activationTarget = targetImpl; }
appendToEventPath( eventImpl, parent, targetImpl, relatedTarget, touchTargets, slotInClosedTree, ); }
if (parent !== null) { parent = getParent(parent); }
slotInClosedTree = false; }
let clearTargetsTupleIndex = -1; const path = getPath(eventImpl); for ( let i = path.length - 1; i >= 0 && clearTargetsTupleIndex === -1; i-- ) { if (path[i].target !== null) { clearTargetsTupleIndex = i; } } const clearTargetsTuple = path[clearTargetsTupleIndex];
clearTargets = (isNode(clearTargetsTuple.target) && isShadowRoot(getRoot(clearTargetsTuple.target))) || (isNode(clearTargetsTuple.relatedTarget) && isShadowRoot(getRoot(clearTargetsTuple.relatedTarget)));
setEventPhase(eventImpl, Event.CAPTURING_PHASE);
for (let i = path.length - 1; i >= 0; --i) { const tuple = path[i];
if (tuple.target === null) { invokeEventListeners(tuple, eventImpl); } }
for (let i = 0; i < path.length; i++) { const tuple = path[i];
if (tuple.target !== null) { setEventPhase(eventImpl, Event.AT_TARGET); } else { setEventPhase(eventImpl, Event.BUBBLING_PHASE); }
if ( (eventImpl.eventPhase === Event.BUBBLING_PHASE && eventImpl.bubbles) || eventImpl.eventPhase === Event.AT_TARGET ) { invokeEventListeners(tuple, eventImpl); } } }
setEventPhase(eventImpl, Event.NONE); setCurrentTarget(eventImpl, null); setPath(eventImpl, []); setDispatched(eventImpl, false); eventImpl.cancelBubble = false; setStopImmediatePropagation(eventImpl, false);
if (clearTargets) { setTarget(eventImpl, null); setRelatedTarget(eventImpl, null); }
// TODO(bartlomieju): invoke activation targets if HTML nodes will be implemented // if (activationTarget !== null) { // if (!eventImpl.defaultPrevented) { // activationTarget._activationBehavior(); // } // }
return !eventImpl.defaultPrevented; }
/** Inner invoking of the event listeners where the resolved listeners are * called. * * Ref: https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke */ function innerInvokeEventListeners( eventImpl, targetListeners, ) { let found = false;
const { type } = eventImpl;
if (!targetListeners || !targetListeners[type]) { return found; }
// Copy event listeners before iterating since the list can be modified during the iteration. const handlers = ArrayPrototypeSlice(targetListeners[type]);
for (let i = 0; i < handlers.length; i++) { const listener = handlers[i];
let capture, once, passive; if (typeof listener.options === "boolean") { capture = listener.options; once = false; passive = false; } else { capture = listener.options.capture; once = listener.options.once; passive = listener.options.passive; }
// Check if the event listener has been removed since the listeners has been cloned. if (!ArrayPrototypeIncludes(targetListeners[type], listener)) { continue; }
found = true;
if ( (eventImpl.eventPhase === Event.CAPTURING_PHASE && !capture) || (eventImpl.eventPhase === Event.BUBBLING_PHASE && capture) ) { continue; }
if (once) { ArrayPrototypeSplice( targetListeners[type], ArrayPrototypeIndexOf(targetListeners[type], listener), 1, ); }
if (passive) { setInPassiveListener(eventImpl, true); }
if (typeof listener.callback === "object") { if (typeof listener.callback.handleEvent === "function") { listener.callback.handleEvent(eventImpl); } } else { FunctionPrototypeCall( listener.callback, eventImpl.currentTarget, eventImpl, ); }
setInPassiveListener(eventImpl, false);
if (getStopImmediatePropagation(eventImpl)) { return found; } }
return found; }
/** Invokes the listeners on a given event path with the supplied event. * * Ref: https://dom.spec.whatwg.org/#concept-event-listener-invoke */ function invokeEventListeners(tuple, eventImpl) { const path = getPath(eventImpl); const tupleIndex = ArrayPrototypeIndexOf(path, tuple); for (let i = tupleIndex; i >= 0; i--) { const t = path[i]; if (t.target) { setTarget(eventImpl, t.target); break; } }
setRelatedTarget(eventImpl, tuple.relatedTarget);
if (eventImpl.cancelBubble) { return; }
setCurrentTarget(eventImpl, tuple.item);
try { innerInvokeEventListeners(eventImpl, getListeners(tuple.item)); } catch (error) { reportException(error); } }
function normalizeEventHandlerOptions( options, ) { if (typeof options === "boolean" || typeof options === "undefined") { return { capture: Boolean(options), }; } else { return options; } }
/** Retarget the target following the spec logic. * * Ref: https://dom.spec.whatwg.org/#retarget */ function retarget(a, b) { while (true) { if (!isNode(a)) { return a; }
const aRoot = a.getRootNode();
if (aRoot) { if ( !isShadowRoot(aRoot) || (isNode(b) && isShadowInclusiveAncestor(aRoot, b)) ) { return a; }
a = getHost(aRoot); } } }
// Accessors for non-public data
const eventTargetData = Symbol();
function setEventTargetData(target) { target[eventTargetData] = getDefaultTargetData(); }
function getAssignedSlot(target) { return Boolean(target?.[eventTargetData]?.assignedSlot); }
function getHasActivationBehavior(target) { return Boolean(target?.[eventTargetData]?.hasActivationBehavior); }
function getHost(target) { return target?.[eventTargetData]?.host ?? null; }
function getListeners(target) { return target?.[eventTargetData]?.listeners ?? {}; }
function getMode(target) { return target?.[eventTargetData]?.mode ?? null; }
function listenerCount(target, type) { return getListeners(target)?.[type]?.length ?? 0; }
function getDefaultTargetData() { return { assignedSlot: false, hasActivationBehavior: false, host: null, listeners: ObjectCreate(null), mode: "", }; }
// This is lazy loaded because there is a circular dependency with AbortSignal. let addEventListenerOptionsConverter;
function lazyAddEventListenerOptionsConverter() { addEventListenerOptionsConverter ??= webidl.createDictionaryConverter( "AddEventListenerOptions", [ { key: "capture", defaultValue: false, converter: webidl.converters.boolean, }, { key: "passive", defaultValue: false, converter: webidl.converters.boolean, }, { key: "once", defaultValue: false, converter: webidl.converters.boolean, }, { key: "signal", converter: webidl.converters.AbortSignal, }, ], ); }
webidl.converters.AddEventListenerOptions = (V, opts) => { if (webidl.type(V) !== "Object" || V === null) { V = { capture: Boolean(V) }; }
lazyAddEventListenerOptionsConverter(); return addEventListenerOptionsConverter(V, opts); };
class EventTarget { constructor() { this[eventTargetData] = getDefaultTargetData(); this[webidl.brand] = webidl.brand; }
addEventListener( type, callback, options, ) { const self = this ?? globalThis; webidl.assertBranded(self, EventTargetPrototype); const prefix = "Failed to execute 'addEventListener' on 'EventTarget'";
webidl.requiredArguments(arguments.length, 2, { prefix, });
options = webidl.converters.AddEventListenerOptions(options, { prefix, context: "Argument 3", });
if (callback === null) { return; }
const { listeners } = self[eventTargetData];
if (!(ReflectHas(listeners, type))) { listeners[type] = []; }
for (const listener of listeners[type]) { if ( ((typeof listener.options === "boolean" && listener.options === options.capture) || (typeof listener.options === "object" && listener.options.capture === options.capture)) && listener.callback === callback ) { return; } } if (options?.signal) { const signal = options?.signal; if (signal.aborted) { // If signal is not null and its aborted flag is set, then return. return; } else { // If listener’s signal is not null, then add the following abort // abort steps to it: Remove an event listener. signal.addEventListener("abort", () => { self.removeEventListener(type, callback, options); }); } }
ArrayPrototypePush(listeners[type], { callback, options }); }
removeEventListener( type, callback, options, ) { const self = this ?? globalThis; webidl.assertBranded(self, EventTargetPrototype); webidl.requiredArguments(arguments.length, 2, { prefix: "Failed to execute 'removeEventListener' on 'EventTarget'", });
const { listeners } = self[eventTargetData]; if (callback !== null && ReflectHas(listeners, type)) { listeners[type] = ArrayPrototypeFilter( listeners[type], (listener) => listener.callback !== callback, ); } else if (callback === null || !listeners[type]) { return; }
options = normalizeEventHandlerOptions(options);
for (let i = 0; i < listeners[type].length; ++i) { const listener = listeners[type][i]; if ( ((typeof listener.options === "boolean" && listener.options === options.capture) || (typeof listener.options === "object" && listener.options.capture === options.capture)) && listener.callback === callback ) { ArrayPrototypeSplice(listeners[type], i, 1); break; } } }
dispatchEvent(event) { // If `this` is not present, then fallback to global scope. We don't use // `globalThis` directly here, because it could be deleted by user. // Instead use saved reference to global scope when the script was // executed. const self = this ?? window; webidl.assertBranded(self, EventTargetPrototype); webidl.requiredArguments(arguments.length, 1, { prefix: "Failed to execute 'dispatchEvent' on 'EventTarget'", });
const { listeners } = self[eventTargetData]; if (!ReflectHas(listeners, event.type)) { setTarget(event, this); return true; }
if (getDispatched(event)) { throw new DOMException("Invalid event state.", "InvalidStateError"); }
if (event.eventPhase !== Event.NONE) { throw new DOMException("Invalid event state.", "InvalidStateError"); }
return dispatch(self, event); }
getParent(_event) { return null; } }
webidl.configurePrototype(EventTarget); const EventTargetPrototype = EventTarget.prototype;
defineEnumerableProps(EventTarget, [ "addEventListener", "removeEventListener", "dispatchEvent", ]);
class ErrorEvent extends Event { #message = ""; #filename = ""; #lineno = ""; #colno = ""; #error = "";
get message() { return this.#message; } get filename() { return this.#filename; } get lineno() { return this.#lineno; } get colno() { return this.#colno; } get error() { return this.#error; }
constructor( type, { bubbles, cancelable, composed, message = "", filename = "", lineno = 0, colno = 0, error, } = {}, ) { super(type, { bubbles: bubbles, cancelable: cancelable, composed: composed, });
this.#message = message; this.#filename = filename; this.#lineno = lineno; this.#colno = colno; this.#error = error; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, this), keys: [ ...new SafeArrayIterator(EVENT_PROPS), "message", "filename", "lineno", "colno", "error", ], })); }
// TODO(lucacasonato): remove when this interface is spec aligned [SymbolToStringTag] = "ErrorEvent"; }
defineEnumerableProps(ErrorEvent, [ "message", "filename", "lineno", "colno", "error", ]);
class CloseEvent extends Event { #wasClean = ""; #code = ""; #reason = "";
get wasClean() { return this.#wasClean; } get code() { return this.#code; } get reason() { return this.#reason; }
constructor(type, { bubbles, cancelable, composed, wasClean = false, code = 0, reason = "", } = {}) { super(type, { bubbles: bubbles, cancelable: cancelable, composed: composed, });
this.#wasClean = wasClean; this.#code = code; this.#reason = reason; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(CloseEvent.prototype, this), keys: [ ...new SafeArrayIterator(EVENT_PROPS), "wasClean", "code", "reason", ], })); } }
class MessageEvent extends Event { get source() { return null; }
constructor(type, eventInitDict) { super(type, { bubbles: eventInitDict?.bubbles ?? false, cancelable: eventInitDict?.cancelable ?? false, composed: eventInitDict?.composed ?? false, });
this.data = eventInitDict?.data ?? null; this.ports = eventInitDict?.ports ?? []; this.origin = eventInitDict?.origin ?? ""; this.lastEventId = eventInitDict?.lastEventId ?? ""; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(MessageEvent.prototype, this), keys: [ ...new SafeArrayIterator(EVENT_PROPS), "data", "origin", "lastEventId", ], })); }
// TODO(lucacasonato): remove when this interface is spec aligned [SymbolToStringTag] = "CloseEvent"; }
class CustomEvent extends Event { #detail = null;
constructor(type, eventInitDict = {}) { super(type, eventInitDict); webidl.requiredArguments(arguments.length, 1, { prefix: "Failed to construct 'CustomEvent'", }); const { detail } = eventInitDict; this.#detail = detail; }
get detail() { return this.#detail; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(CustomEvent.prototype, this), keys: [ ...new SafeArrayIterator(EVENT_PROPS), "detail", ], })); }
// TODO(lucacasonato): remove when this interface is spec aligned [SymbolToStringTag] = "CustomEvent"; }
ReflectDefineProperty(CustomEvent.prototype, "detail", { enumerable: true, });
// ProgressEvent could also be used in other DOM progress event emits. // Current use is for FileReader. class ProgressEvent extends Event { constructor(type, eventInitDict = {}) { super(type, eventInitDict);
this.lengthComputable = eventInitDict?.lengthComputable ?? false; this.loaded = eventInitDict?.loaded ?? 0; this.total = eventInitDict?.total ?? 0; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(ProgressEvent.prototype, this), keys: [ ...new SafeArrayIterator(EVENT_PROPS), "lengthComputable", "loaded", "total", ], })); }
// TODO(lucacasonato): remove when this interface is spec aligned [SymbolToStringTag] = "ProgressEvent"; }
class PromiseRejectionEvent extends Event { #promise = null; #reason = null;
get promise() { return this.#promise; } get reason() { return this.#reason; }
constructor( type, { bubbles, cancelable, composed, promise, reason, } = {}, ) { super(type, { bubbles: bubbles, cancelable: cancelable, composed: composed, });
this.#promise = promise; this.#reason = reason; }
[SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: this instanceof PromiseRejectionEvent, keys: [ ...EVENT_PROPS, "promise", "reason", ], })); }
// TODO(lucacasonato): remove when this interface is spec aligned [SymbolToStringTag] = "PromiseRejectionEvent"; }
defineEnumerableProps(PromiseRejectionEvent, [ "promise", "reason", ]);
const _eventHandlers = Symbol("eventHandlers");
function makeWrappedHandler(handler, isSpecialErrorEventHandler) { function wrappedHandler(evt) { if (typeof wrappedHandler.handler !== "function") { return; }
if ( isSpecialErrorEventHandler && ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, evt) && evt.type === "error" ) { const ret = FunctionPrototypeCall( wrappedHandler.handler, this, evt.message, evt.filename, evt.lineno, evt.colno, evt.error, ); if (ret === true) { evt.preventDefault(); } return; }
return FunctionPrototypeCall(wrappedHandler.handler, this, evt); } wrappedHandler.handler = handler; return wrappedHandler; }
// `init` is an optional function that will be called the first time that the // event handler property is set. It will be called with the object on which // the property is set as its argument. // `isSpecialErrorEventHandler` can be set to true to opt into the special // behavior of event handlers for the "error" event in a global scope. function defineEventHandler( emitter, name, init = undefined, isSpecialErrorEventHandler = false, ) { // HTML specification section 8.1.7.1 ObjectDefineProperty(emitter, `on${name}`, { get() { if (!this[_eventHandlers]) { return null; }
return MapPrototypeGet(this[_eventHandlers], name)?.handler ?? null; }, set(value) { // All three Web IDL event handler types are nullable callback functions // with the [LegacyTreatNonObjectAsNull] extended attribute, meaning // anything other than an object is treated as null. if (typeof value !== "object" && typeof value !== "function") { value = null; }
if (!this[_eventHandlers]) { this[_eventHandlers] = new Map(); } let handlerWrapper = MapPrototypeGet(this[_eventHandlers], name); if (handlerWrapper) { handlerWrapper.handler = value; } else if (value !== null) { handlerWrapper = makeWrappedHandler( value, isSpecialErrorEventHandler, ); this.addEventListener(name, handlerWrapper); init?.(this); } MapPrototypeSet(this[_eventHandlers], name, handlerWrapper); }, configurable: true, enumerable: true, }); }
let reportExceptionStackedCalls = 0;
// https://html.spec.whatwg.org/#report-the-exception function reportException(error) { reportExceptionStackedCalls++; const jsError = core.destructureError(error); const message = jsError.exceptionMessage; let filename = ""; let lineno = 0; let colno = 0; if (jsError.frames.length > 0) { filename = jsError.frames[0].fileName; lineno = jsError.frames[0].lineNumber; colno = jsError.frames[0].columnNumber; } else { const jsError = core.destructureError(new Error()); for (const frame of jsError.frames) { if ( typeof frame.fileName == "string" && !StringPrototypeStartsWith(frame.fileName, "deno:") ) { filename = frame.fileName; lineno = frame.lineNumber; colno = frame.columnNumber; break; } } } const event = new ErrorEvent("error", { cancelable: true, message, filename, lineno, colno, error, }); // Avoid recursing `reportException()` via error handlers more than once. if (reportExceptionStackedCalls > 1 || window.dispatchEvent(event)) { ops.op_dispatch_exception(error); } reportExceptionStackedCalls--; }
function checkThis(thisArg) { if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) { throw new TypeError("Illegal invocation"); } }
// https://html.spec.whatwg.org/#dom-reporterror function reportError(error) { checkThis(this); const prefix = "Failed to call 'reportError'"; webidl.requiredArguments(arguments.length, 1, { prefix }); reportException(error); }
window.__bootstrap.eventTarget = { EventTarget, setEventTargetData, listenerCount, }; window.__bootstrap.event = { reportException, setIsTrusted, setTarget, defineEventHandler, Event, ErrorEvent, CloseEvent, MessageEvent, CustomEvent, ProgressEvent, PromiseRejectionEvent, reportError, };})(this);
Version Info