diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 6382849593909d..c267050bf614d6 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -76,6 +76,7 @@ const { now } = require('internal/perf/utils'); const kType = Symbol('type'); const kDetail = Symbol('detail'); +const kInPassiveListener = Symbol('kInPassiveListener'); const isTrustedSet = new SafeWeakSet(); const isTrusted = ObjectGetOwnPropertyDescriptor({ @@ -127,6 +128,7 @@ class Event { this[kTarget] = null; this[kIsBeingDispatched] = false; + this[kInPassiveListener] = false; } /** @@ -178,6 +180,7 @@ class Event { preventDefault() { if (!isEvent(this)) throw new ERR_INVALID_THIS('Event'); + if (!this.#cancelable || this[kInPassiveListener]) return; this.#defaultPrevented = true; } @@ -266,6 +269,19 @@ class Event { return !this.#cancelable || !this.#defaultPrevented; } + /** + * @type {boolean} + */ + set returnValue(value) { + if (!isEvent(this)) + throw new ERR_INVALID_THIS('Event'); + + if (!value) { + if (!this.#cancelable || this[kInPassiveListener]) return; + this.#defaultPrevented = true; + } + } + /** * @type {boolean} */ @@ -760,7 +776,6 @@ class EventTarget { throw new ERR_EVENT_RECURSION(event.type); this[kHybridDispatch](event, event.type, event); - return event.defaultPrevented !== true; } @@ -813,8 +828,8 @@ class EventTarget { this[kRemoveListener](root.size, type, listener, capture); } + let arg; try { - let arg; if (handler.isNodeStyleListener) { arg = nodeValue; } else { @@ -824,6 +839,9 @@ class EventTarget { handler.callback.deref() : handler.callback; let result; if (callback) { + if (handler.passive && !handler.isNodeStyleListener) { + arg[kInPassiveListener] = true; + } result = FunctionPrototypeCall(callback, this, arg); if (!handler.isNodeStyleListener) { arg[kIsBeingDispatched] = false; @@ -833,6 +851,9 @@ class EventTarget { addCatch(result); } catch (err) { emitUncaughtException(err); + } finally { + if (arg?.[kInPassiveListener]) + arg[kInPassiveListener] = false; } handler = next; diff --git a/test/parallel/test-whatwg-events-add-event-listener-options-passive.js b/test/parallel/test-whatwg-events-add-event-listener-options-passive.js index 97984bd9aff828..0299c7fa5fb0cc 100644 --- a/test/parallel/test-whatwg-events-add-event-listener-options-passive.js +++ b/test/parallel/test-whatwg-events-add-event-listener-options-passive.js @@ -1,6 +1,6 @@ 'use strict'; -const common = require('../common'); +require('../common'); // Manually converted from https://github.com/web-platform-tests/wpt/blob/master/dom/events/AddEventListenerOptions-passive.html // in order to define the `document` ourselves @@ -58,7 +58,6 @@ const { testPassiveValue({}, true); testPassiveValue({ passive: false }, true); - common.skip('TODO: passive listeners is still broken'); testPassiveValue({ passive: 1 }, false); testPassiveValue({ passive: true }, false); testPassiveValue({ passive: 0 }, true); diff --git a/test/wpt/status/dom/events.json b/test/wpt/status/dom/events.json index c0f4104c452b85..8109e2372adfb8 100644 --- a/test/wpt/status/dom/events.json +++ b/test/wpt/status/dom/events.json @@ -1,13 +1,4 @@ { - "AddEventListenerOptions-passive.any.js": { - "fail": { - "expected": [ - "preventDefault should be ignored if-and-only-if the passive option is true", - "returnValue should be ignored if-and-only-if the passive option is true", - "passive behavior of one listener should be unaffected by the presence of other listeners" - ] - } - }, "Event-dispatch-listener-order.window.js": { "skip": "document is not defined" },