From f643cf4d2b8fae1e0f301fb6e53f58c89cacc2c3 Mon Sep 17 00:00:00 2001 From: Benjamin Gruenbaum Date: Thu, 28 May 2020 17:33:21 +0300 Subject: [PATCH 1/5] event: cancelBubble is a property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Event#cancelBubble is property (and not a function). Change Event#cancelBubble to a property and add a test. PR-URL: https://github.com/nodejs/node/pull/33613 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Ruben Bridgewater Reviewed-By: Juan José Arboleda --- lib/internal/event_target.js | 13 +++++++++---- test/parallel/test-eventtarget.js | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 133edc23b2423a..d1af4db3c58dd9 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -36,12 +36,13 @@ class Event { #cancelable = false; #timestamp = perf_hooks.performance.now(); - // Neither of these are currently used in the Node.js implementation + // None of these are currently used in the Node.js implementation // of EventTarget because there is no concept of bubbling or // composition. We preserve their values in Event but they are // non-ops and do not carry any semantics in Node.js #bubbles = false; #composed = false; + #propagationStopped = false; constructor(type, options) { @@ -54,6 +55,7 @@ class Event { this.#cancelable = !!cancelable; this.#bubbles = !!bubbles; this.#composed = !!composed; + this.#propagationStopped = false; this.#type = String(type); // isTrusted is special (LegacyUnforgeable) Object.defineProperty(this, 'isTrusted', { @@ -113,11 +115,14 @@ class Event { get eventPhase() { return this[kTarget] ? 2 : 0; // Equivalent to AT_TARGET or NONE } - cancelBubble() { - // Non-op in Node.js. Alias for stopPropagation + get cancelBubble() { return this.#propagationStopped; } + set cancelBubble(value) { + if (value) { + this.stopPropagation(); + } } stopPropagation() { - // Non-op in Node.js + this.#propagationStopped = true; } get [Symbol.toStringTag]() { return 'Event'; } diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index 82a89caae1fea4..f9a95a8983cddd 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -36,6 +36,7 @@ ok(EventTarget); strictEqual(ev.composed, false); strictEqual(ev.isTrusted, false); strictEqual(ev.eventPhase, 0); + strictEqual(ev.cancelBubble, false); // Not cancelable ev.preventDefault(); @@ -50,6 +51,24 @@ ok(EventTarget); const ev = new Event('foo', {}, {}); strictEqual(ev.type, 'foo'); } +{ +const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.cancelBubble = true; + strictEqual(ev.cancelBubble, true); +} +{ + const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.stopPropagation(); + strictEqual(ev.cancelBubble, true); +} +{ + const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.cancelBubble = 'some-truthy-value'; + strictEqual(ev.cancelBubble, true); +} { const ev = new Event('foo', { cancelable: true }); strictEqual(ev.type, 'foo'); From 07dcb75b177d9c8d0e02cded27a6fc5f5d587e6d Mon Sep 17 00:00:00 2001 From: Benjamin Gruenbaum Date: Thu, 28 May 2020 19:08:43 +0300 Subject: [PATCH 2/5] events: support useCapture boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/33618 Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater Reviewed-By: Michaël Zasso Reviewed-By: Anna Henningsen --- lib/internal/event_target.js | 3 +++ test/parallel/test-eventtarget.js | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index d1af4db3c58dd9..cf94bcbe7bf387 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -412,6 +412,9 @@ function validateListener(listener) { } function validateEventListenerOptions(options) { + if (typeof options === 'boolean') { + options = { capture: options }; + } if (options == null || typeof options !== 'object') throw new ERR_INVALID_ARG_TYPE('options', 'object', options); const { diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index f9a95a8983cddd..f032b2fedb715a 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -151,7 +151,14 @@ const ev = new Event('foo'); eventTarget.addEventListener('foo', (event) => event.preventDefault()); ok(!eventTarget.dispatchEvent(event)); } - +{ + // Adding event listeners with a boolean useCapture + const eventTarget = new EventTarget(); + const event = new Event('foo'); + const fn = common.mustCall((event) => strictEqual(event.type, 'foo')); + eventTarget.addEventListener('foo', fn, false); + eventTarget.dispatchEvent(event); +} { const eventTarget = new NodeEventTarget(); strictEqual(eventTarget.listenerCount('foo'), 0); From b2b95eb7543d5b992609df95c12f2f9dff67fdd4 Mon Sep 17 00:00:00 2001 From: Benjamin Gruenbaum Date: Thu, 28 May 2020 17:43:11 +0300 Subject: [PATCH 3/5] events: set target property to null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/33615 Reviewed-By: Ruben Bridgewater Reviewed-By: Zeyu Yang Reviewed-By: James M Snell Reviewed-By: Juan José Arboleda --- lib/internal/event_target.js | 3 ++- test/parallel/test-eventtarget.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index cf94bcbe7bf387..e371ee06a1b83b 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -64,6 +64,7 @@ class Event { enumerable: true, configurable: false }); + this[kTarget] = null; } [customInspectSymbol](depth, options) { @@ -245,7 +246,7 @@ class EventTarget { } if (this.#emitting.has(event.type) || - event[kTarget] !== undefined) { + event[kTarget] !== null) { throw new ERR_EVENT_RECURSION(event.type); } diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index f032b2fedb715a..e47dac6fc2f48c 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -385,6 +385,7 @@ const ev = new Event('foo'); { const target = new EventTarget(); const event = new Event('foo'); + strictEqual(event.target, null); target.addEventListener('foo', common.mustCall((event) => { strictEqual(event.target, target); strictEqual(event.currentTarget, target); From df4eda20a008530edaf7f18ff5e472b1f429c867 Mon Sep 17 00:00:00 2001 From: Benjamin Gruenbaum Date: Thu, 28 May 2020 21:46:18 +0300 Subject: [PATCH 4/5] events: add event-target tests PR-URL: https://github.com/nodejs/node/pull/33623 Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- test/parallel/test-eventtarget.js | 34 +++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index e47dac6fc2f48c..38fba9e09140ca 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -15,7 +15,7 @@ const { throws, } = require('assert'); -const { once } = require('events'); +const { once, on } = require('events'); // The globals are defined. ok(Event); @@ -52,7 +52,7 @@ ok(EventTarget); strictEqual(ev.type, 'foo'); } { -const ev = new Event('foo'); + const ev = new Event('foo'); strictEqual(ev.cancelBubble, false); ev.cancelBubble = true; strictEqual(ev.cancelBubble, true); @@ -438,3 +438,33 @@ const ev = new Event('foo'); const event = new Event(); strictEqual(event.toString(), '[object Event]'); } +{ + const target = new EventTarget(); + const ev = new Event('toString'); + const fn = common.mustCall((event) => strictEqual(event.type, 'toString')); + target.addEventListener('toString', fn); + target.dispatchEvent(ev); +} +{ + const target = new EventTarget(); + const ev = new Event('__proto__'); + const fn = common.mustCall((event) => strictEqual(event.type, '__proto__')); + target.addEventListener('__proto__', fn); + target.dispatchEvent(ev); +} + +(async () => { + // test NodeEventTarget async-iterability + const emitter = new NodeEventTarget(); + const event = new Event('foo'); + const interval = setInterval(() => emitter.dispatchEvent(event), 0); + let count = 0; + for await (const [ item ] of on(emitter, 'foo')) { + count++; + strictEqual(item.type, 'foo'); + if (count > 5) { + break; + } + } + clearInterval(interval); +})().then(common.mustCall()); From fdb470157f9896b8cf3d3725642791c2c831ca36 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Sun, 31 May 2020 14:48:04 +0300 Subject: [PATCH 5/5] test: fix test-eventtarget --- test/parallel/test-eventtarget.js | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index 38fba9e09140ca..579ecfd75b3471 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -15,7 +15,7 @@ const { throws, } = require('assert'); -const { once, on } = require('events'); +const { once } = require('events'); // The globals are defined. ok(Event); @@ -435,7 +435,7 @@ ok(EventTarget); { const target = new EventTarget(); strictEqual(target.toString(), '[object EventTarget]'); - const event = new Event(); + const event = new Event('foo'); strictEqual(event.toString(), '[object Event]'); } { @@ -452,19 +452,3 @@ ok(EventTarget); target.addEventListener('__proto__', fn); target.dispatchEvent(ev); } - -(async () => { - // test NodeEventTarget async-iterability - const emitter = new NodeEventTarget(); - const event = new Event('foo'); - const interval = setInterval(() => emitter.dispatchEvent(event), 0); - let count = 0; - for await (const [ item ] of on(emitter, 'foo')) { - count++; - strictEqual(item.type, 'foo'); - if (count > 5) { - break; - } - } - clearInterval(interval); -})().then(common.mustCall());