mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
events: Handle a range of this values for dispatchEvent
On the web, dispatchEvent is finicky about its `this` value. An exception is thrown for `this` values which are not an EventTarget. PR-URL: https://github.com/nodejs/node/pull/34015 Reviewed-By: Denys Otrishko <shishugi@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
1 parent
4b3654e923
commit
a30babf672
2 files changed
+47
-1
No files matched your search
@@ -9,6 +9,7 @@ const {
|
||||
Object,
|
||||
Set,
|
||||
Symbol,
|
||||
SymbolFor,
|
||||
SymbolToStringTag,
|
||||
} = primordials;
|
||||
|
||||
@@ -16,7 +17,8 @@ const {
|
||||
codes: {
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
ERR_EVENT_RECURSION,
|
||||
ERR_MISSING_ARGS
|
||||
ERR_MISSING_ARGS,
|
||||
ERR_INVALID_THIS,
|
||||
}
|
||||
} = require('internal/errors');
|
||||
const { validateInteger, validateObject } = require('internal/validators');
|
||||
@@ -24,6 +26,8 @@ const { validateInteger, validateObject } = require('internal/validators');
|
||||
const { customInspectSymbol } = require('internal/util');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const kIsEventTarget = SymbolFor('nodejs.event_target');
|
||||
|
||||
const kEvents = Symbol('kEvents');
|
||||
const kStop = Symbol('kStop');
|
||||
const kTarget = Symbol('kTarget');
|
||||
@@ -185,6 +189,10 @@ class Listener {
|
||||
}
|
||||
|
||||
class EventTarget {
|
||||
// Used in checking whether an object is an EventTarget. This is a well-known
|
||||
// symbol as EventTarget may be used cross-realm. See discussion in #33661.
|
||||
static [kIsEventTarget] = true;
|
||||
|
||||
[kEvents] = new Map();
|
||||
#emitting = new Set();
|
||||
|
||||
@@ -257,6 +265,10 @@ class EventTarget {
|
||||
throw new ERR_INVALID_ARG_TYPE('event', 'Event', event);
|
||||
}
|
||||
|
||||
if (!isEventTarget(this)) {
|
||||
throw new ERR_INVALID_THIS('EventTarget');
|
||||
}
|
||||
|
||||
if (this.#emitting.has(event.type) ||
|
||||
event[kTarget] !== null) {
|
||||
throw new ERR_EVENT_RECURSION(event.type);
|
||||
@@ -438,6 +450,15 @@ function validateEventListenerOptions(options) {
|
||||
};
|
||||
}
|
||||
|
||||
// Test whether the argument is an event object. This is far from a fool-proof
|
||||
// test, for example this input will result in a false positive:
|
||||
// > isEventTarget({ constructor: EventTarget })
|
||||
// It stands in its current implementation as a compromise. For the relevant
|
||||
// discussion, see #33661.
|
||||
function isEventTarget(obj) {
|
||||
return obj && obj.constructor && obj.constructor[kIsEventTarget];
|
||||
}
|
||||
|
||||
function addCatch(that, promise, event) {
|
||||
const then = promise.then;
|
||||
if (typeof then === 'function') {
|
||||
|
||||
@@ -439,3 +439,28 @@ ok(EventTarget);
|
||||
const event = new Event('');
|
||||
strictEqual(event.toString(), '[object Event]');
|
||||
}
|
||||
|
||||
{
|
||||
// `this` value of dispatchEvent
|
||||
const target = new EventTarget();
|
||||
const target2 = new EventTarget();
|
||||
const event = new Event('foo');
|
||||
|
||||
ok(target.dispatchEvent.call(target2, event));
|
||||
|
||||
[
|
||||
'foo',
|
||||
{},
|
||||
[],
|
||||
1,
|
||||
null,
|
||||
undefined,
|
||||
false,
|
||||
Symbol(),
|
||||
/a/
|
||||
].forEach((i) => {
|
||||
throws(() => target.dispatchEvent.call(i, event), {
|
||||
code: 'ERR_INVALID_THIS'
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user