-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Passive event listener wrapper #10721
Conversation
65843c4
to
0d3bb38
Compare
@erwinmombay is updating the type-checker to support passive events for this to pass |
b90a2d6
to
1440784
Compare
i am close to updating. theres a dozen of broken types now though that i need to fix |
src/event-helper.js
Outdated
* @return {!UnlistenDef} | ||
*/ | ||
export function listenOnce(element, eventType, listener, opt_capture) { | ||
export function listenOnce(element, eventType, listener, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you add to listenPromise*
as well, for completeness
src/event-helper-listen.js
Outdated
|
||
// Test whether browser supports the passive option or not | ||
let passiveSupported = false; | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couple of unit tests to make sure detection is works as browser's implementation may change. Ideally tests call the top-level exported listen
, mock the addEventListener
for test-passive
to either support or not support and then spy on addEventListener
and removeEventListener
to make sure the third arg is correct
src/event-helper.js
Outdated
@@ -50,11 +50,12 @@ export function createCustomEvent(win, type, detail, opt_eventInit) { | |||
* @param {string} eventType | |||
* @param {function(!Event)} listener | |||
* @param {boolean=} opt_capture |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to make this
@param {boolean|EventListenerOptions}
opt_catureOrOptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's our implementation and we already implement once
through listenOncePromise
, I thought there's really no point from passing an object when the only two options are capture
and passive
, but if you think it should be that way then sure!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to add more arguments when more options are added.
src/event-helper-listen.js
Outdated
@@ -41,11 +43,34 @@ export function internalListenImplementation(element, eventType, listener, | |||
throw e; | |||
} | |||
}; | |||
|
|||
// Test whether browser supports the passive option or not | |||
let passiveSupported = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cache this value in a global and only run the feature detection code once per window.
src/event-helper-listen.js
Outdated
// Test whether browser supports the passive option or not | ||
let passiveSupported = false; | ||
try { | ||
const options = Object.defineProperty({}, 'passive', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The polyfill is more general if you ask for capture instead. That way this code doesn't have to change for further options. If people really need this test, they can export a function for feature detection.
…n possible. Needs ampproject#10721 to land first.
Usage in #10901 |
Ready for final review, will need to revert back to using |
@@ -49,12 +49,12 @@ export function createCustomEvent(win, type, detail, opt_eventInit) { | |||
* @param {!EventTarget} element | |||
* @param {string} eventType | |||
* @param {function(!Event)} listener | |||
* @param {boolean=} opt_capture | |||
* @param {Object=} opt_evtListenerOpts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be boolean|Object=
? If not, you need to change all callsites.
src/event-helper-listen.js
Outdated
* addEventListener or not | ||
* @enum {string} | ||
*/ | ||
const optTest = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've used undefined
, true
, and false
elsewhere in the project.
src/event-helper-listen.js
Outdated
}; | ||
const optsSupported = detectEvtListenerOptsSupport(); | ||
let capture = false; | ||
if (opt_evtListenerOpts && opt_evtListenerOpts.capture) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unnecessary to check for opt_evtListenerOpts.capture
localElement.removeEventListener( | ||
eventType, | ||
wrapped, | ||
optsSupported ? opt_evtListenerOpts : capture |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only capture
matters for #removeEventListener
per https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener#Matching_event_listeners_for_removal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did it based on
It's worth noting that some browser releases have been inconsistent on this, and unless you have specific reasons otherwise, it's probably wise to use the same values used for the call to addEventListener() when calling removeEventListener().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/event-helper-listen.js
Outdated
try { | ||
let optsSupported = self.optsSupported; | ||
const options = Object.defineProperty({}, 'capture', { | ||
get: function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use a object with getter:
const options = {
get capture() {
optsSupported = true;
},
}
src/event-helper-listen.js
Outdated
optsSupported = optTest.SUPPORTED; | ||
}, | ||
}); | ||
self.addEventListener('test-opts', null, options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be cleaned up.
src/event-helper-listen.js
Outdated
* @suppress {checkTypes} | ||
*/ | ||
export function detectEvtListenerOptsSupport() { | ||
if (!self.optsSupported) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting this on self
is unnecessary, just use a module level variable. See https://github.com/ampproject/amphtml/blob/master/src/dom.js#L375-L400.
@@ -24,32 +31,79 @@ | |||
* @param {!EventTarget} element | |||
* @param {string} eventType | |||
* @param {function(!Event)} listener | |||
* @param {boolean=} opt_capture | |||
* @param {Object=} opt_evtListenerOpts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm: do you want to update all callers to only use options struct? Or will you continue to allow capture
as boolean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not find any callers that use capture
actually, most use the native addEventListener
instead (please confirm). So if we're starting this, maybe we should reinforce using options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. If the case, let's definitely go with options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aghassemi could you please confirm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it compiles it is is cool. That is what they type checker is for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't find any usages either and yeah type check should catch them anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one request
src/event-helper-listen.js
Outdated
/** | ||
* Resets the test for whether addEventListener supports options or not. | ||
*/ | ||
export function resetEvtListenerOptsSupport() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add ForTesting
suffix to the name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits.
src/event-helper-listen.js
Outdated
// Only run the test once | ||
if (self.optsSupported != optTest.NOT_RUN) { | ||
return self.optsSupported == optTest.SUPPORTED; | ||
if (typeof optsSupported != 'undefined') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just check for === undefined
.
src/event-helper-listen.js
Outdated
*/ | ||
export function detectEvtListenerOptsSupport() { | ||
// Only run the test once | ||
if (typeof optsSupported != 'undefined') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optsSupported !== undefined
src/event-helper-listen.js
Outdated
optsSupported = true; | ||
}, | ||
}; | ||
self.addEventListener('test-opts', null, options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be cleaned up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaned up as in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#removeEventListener
a84a879
to
a280211
Compare
test failure and we can merge after |
For future reference, the test was failing because |
@cramforce Blocked on your review, PTAL |
…n possible. Needs #10721 to land first.
…n possible. Needs ampproject#10721 to land first.
Changes
passive
option to the event listener to make use of the newaddEventListener
interface.Re-opened #5105 to remove
@suppress typechecks
, and changeObject
toAddEventListenerOptions
when the Closure Compiler extern is updatedCloses #4819 , Relates to #5109