Skip to content

Commit

Permalink
events: allow an event to be dispatched multiple times
Browse files Browse the repository at this point in the history
Use a different flag to prevent recursive dispatching.

PR-URL: #39395
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
lpinca authored and BethGriggs committed Jul 29, 2021
1 parent 6f2989c commit 1fb0954
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
18 changes: 13 additions & 5 deletions lib/internal/event_target.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const {
} = EventEmitter;

const kEvents = Symbol('kEvents');
const kIsBeingDispatched = Symbol('kIsBeingDispatched');
const kStop = Symbol('kStop');
const kTarget = Symbol('kTarget');
const kHandlers = Symbol('khandlers');
Expand Down Expand Up @@ -105,6 +106,7 @@ class Event {
configurable: false
});
this[kTarget] = null;
this[kIsBeingDispatched] = false;
}

[customInspectSymbol](depth, options) {
Expand Down Expand Up @@ -151,12 +153,12 @@ class Event {
// These are not supported in Node.js and are provided purely for
// API completeness.

composedPath() { return this[kTarget] ? [this[kTarget]] : []; }
composedPath() { return this[kIsBeingDispatched] ? [this[kTarget]] : []; }
get returnValue() { return !this.defaultPrevented; }
get bubbles() { return this[kBubbles]; }
get composed() { return this[kComposed]; }
get eventPhase() {
return this[kTarget] ? Event.AT_TARGET : Event.NONE;
return this[kIsBeingDispatched] ? Event.AT_TARGET : Event.NONE;
}
get cancelBubble() { return this[kPropagationStopped]; }
set cancelBubble(value) {
Expand Down Expand Up @@ -397,7 +399,7 @@ class EventTarget {
if (!isEventTarget(this))
throw new ERR_INVALID_THIS('EventTarget');

if (event[kTarget] !== null)
if (event[kIsBeingDispatched])
throw new ERR_EVENT_RECURSION(event.type);

this[kHybridDispatch](event, event.type, event);
Expand All @@ -410,11 +412,14 @@ class EventTarget {
if (event === undefined) {
event = this[kCreateEvent](nodeValue, type);
event[kTarget] = this;
event[kIsBeingDispatched] = true;
}
return event;
};
if (event !== undefined)
if (event !== undefined) {
event[kTarget] = this;
event[kIsBeingDispatched] = true;
}

const root = this[kEvents].get(type);
if (root === undefined || root.next === undefined)
Expand Down Expand Up @@ -453,6 +458,9 @@ class EventTarget {
let result;
if (callback) {
result = FunctionPrototypeCall(callback, this, arg);
if (!handler.isNodeStyleListener) {
arg[kIsBeingDispatched] = false;
}
}
if (result !== undefined && result !== null)
addCatch(result);
Expand All @@ -464,7 +472,7 @@ class EventTarget {
}

if (event !== undefined)
event[kTarget] = undefined;
event[kIsBeingDispatched] = false;
}

[kCreateEvent](nodeValue, type) {
Expand Down
30 changes: 30 additions & 0 deletions test/parallel/test-eventtarget.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,36 @@ let asyncTest = Promise.resolve();
eventTarget.dispatchEvent(ev);
}

{
// Same event dispatched multiple times.
const event = new Event('foo');
const eventTarget1 = new EventTarget();
const eventTarget2 = new EventTarget();

eventTarget1.addEventListener('foo', common.mustCall((event) => {
strictEqual(event.eventPhase, Event.AT_TARGET);
strictEqual(event.target, eventTarget1);
deepStrictEqual(event.composedPath(), [eventTarget1]);
}));

eventTarget2.addEventListener('foo', common.mustCall((event) => {
strictEqual(event.eventPhase, Event.AT_TARGET);
strictEqual(event.target, eventTarget2);
deepStrictEqual(event.composedPath(), [eventTarget2]);
}));

eventTarget1.dispatchEvent(event);
strictEqual(event.eventPhase, Event.NONE);
strictEqual(event.target, eventTarget1);
deepStrictEqual(event.composedPath(), []);


eventTarget2.dispatchEvent(event);
strictEqual(event.eventPhase, Event.NONE);
strictEqual(event.target, eventTarget2);
deepStrictEqual(event.composedPath(), []);
}

{
const eventTarget = new EventTarget();
const event = new Event('foo', { cancelable: true });
Expand Down

0 comments on commit 1fb0954

Please sign in to comment.