Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6be31fb

Browse filesBrowse files
Amemometargos
authored andcommitted
lib: implement passive listener behavior per spec
Implements the WHATWG DOM specification for passive event listeners, ensuring that calls to `preventDefault()` are correctly ignored within a passive listener context. An internal `kInPassiveListener` state is added to the Event object to track when a passive listener is executing. The `preventDefault()` method and the `returnValue` setter are modified to check this state, as well as the event's `cancelable` property. This state is reliably cleaned up within a `finally` block to prevent state pollution in case a listener throws an error. This resolves previously failing Web Platform Tests (WPT) in `AddEventListenerOptions-passive.any.js`. Refs: https://dom.spec.whatwg.org/#dom-event-preventdefault PR-URL: #59995 Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com> Reviewed-By: Mattias Buelens <mattias@buelens.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Jason Zhang <xzha4350@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent b3295b8 commit 6be31fb
Copy full SHA for 6be31fb

File tree

Expand file treeCollapse file tree

3 files changed

+24
-13
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+24
-13
lines changed
Open diff view settings
Collapse file

‎lib/internal/event_target.js‎

Copy file name to clipboardExpand all lines: lib/internal/event_target.js
+23-2Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const { now } = require('internal/perf/utils');
7676

7777
const kType = Symbol('type');
7878
const kDetail = Symbol('detail');
79+
const kInPassiveListener = Symbol('kInPassiveListener');
7980

8081
const isTrustedSet = new SafeWeakSet();
8182
const isTrusted = ObjectGetOwnPropertyDescriptor({
@@ -127,6 +128,7 @@ class Event {
127128

128129
this[kTarget] = null;
129130
this[kIsBeingDispatched] = false;
131+
this[kInPassiveListener] = false;
130132
}
131133

132134
/**
@@ -178,6 +180,7 @@ class Event {
178180
preventDefault() {
179181
if (!isEvent(this))
180182
throw new ERR_INVALID_THIS('Event');
183+
if (!this.#cancelable || this[kInPassiveListener]) return;
181184
this.#defaultPrevented = true;
182185
}
183186

@@ -266,6 +269,19 @@ class Event {
266269
return !this.#cancelable || !this.#defaultPrevented;
267270
}
268271

272+
/**
273+
* @type {boolean}
274+
*/
275+
set returnValue(value) {
276+
if (!isEvent(this))
277+
throw new ERR_INVALID_THIS('Event');
278+
279+
if (!value) {
280+
if (!this.#cancelable || this[kInPassiveListener]) return;
281+
this.#defaultPrevented = true;
282+
}
283+
}
284+
269285
/**
270286
* @type {boolean}
271287
*/
@@ -760,7 +776,6 @@ class EventTarget {
760776
throw new ERR_EVENT_RECURSION(event.type);
761777

762778
this[kHybridDispatch](event, event.type, event);
763-
764779
return event.defaultPrevented !== true;
765780
}
766781

@@ -813,8 +828,8 @@ class EventTarget {
813828
this[kRemoveListener](root.size, type, listener, capture);
814829
}
815830

831+
let arg;
816832
try {
817-
let arg;
818833
if (handler.isNodeStyleListener) {
819834
arg = nodeValue;
820835
} else {
@@ -824,6 +839,9 @@ class EventTarget {
824839
handler.callback.deref() : handler.callback;
825840
let result;
826841
if (callback) {
842+
if (handler.passive && !handler.isNodeStyleListener) {
843+
arg[kInPassiveListener] = true;
844+
}
827845
result = FunctionPrototypeCall(callback, this, arg);
828846
if (!handler.isNodeStyleListener) {
829847
arg[kIsBeingDispatched] = false;
@@ -833,6 +851,9 @@ class EventTarget {
833851
addCatch(result);
834852
} catch (err) {
835853
emitUncaughtException(err);
854+
} finally {
855+
if (arg?.[kInPassiveListener])
856+
arg[kInPassiveListener] = false;
836857
}
837858

838859
handler = next;
Collapse file

‎test/parallel/test-whatwg-events-add-event-listener-options-passive.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-whatwg-events-add-event-listener-options-passive.js
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const common = require('../common');
3+
require('../common');
44

55
// Manually converted from https://github.com/web-platform-tests/wpt/blob/master/dom/events/AddEventListenerOptions-passive.html
66
// in order to define the `document` ourselves
@@ -58,7 +58,6 @@ const {
5858
testPassiveValue({}, true);
5959
testPassiveValue({ passive: false }, true);
6060

61-
common.skip('TODO: passive listeners is still broken');
6261
testPassiveValue({ passive: 1 }, false);
6362
testPassiveValue({ passive: true }, false);
6463
testPassiveValue({ passive: 0 }, true);
Collapse file

‎test/wpt/status/dom/events.json‎

Copy file name to clipboardExpand all lines: test/wpt/status/dom/events.json
-9Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
{
2-
"AddEventListenerOptions-passive.any.js": {
3-
"fail": {
4-
"expected": [
5-
"preventDefault should be ignored if-and-only-if the passive option is true",
6-
"returnValue should be ignored if-and-only-if the passive option is true",
7-
"passive behavior of one listener should be unaffected by the presence of other listeners"
8-
]
9-
}
10-
},
112
"Event-dispatch-listener-order.window.js": {
123
"skip": "document is not defined"
134
},

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.