Skip to content
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

Merged
merged 9 commits into from
Aug 18, 2017
Merged

Conversation

wassgha
Copy link
Contributor

@wassgha wassgha commented Jul 31, 2017

Changes

  • Added passive option to the event listener to make use of the new addEventListener interface.
  • Possible use case includes preventing scrolling when dragging

Re-opened #5105 to remove @suppress typechecks, and change Object to AddEventListenerOptions when the Closure Compiler extern is updated

Closes #4819 , Relates to #5109

@wassgha wassgha requested a review from aghassemi July 31, 2017 08:08
@wassgha wassgha force-pushed the video-dock-ui branch 6 times, most recently from 65843c4 to 0d3bb38 Compare July 31, 2017 18:20
@wassgha
Copy link
Contributor Author

wassgha commented Jul 31, 2017

@erwinmombay is updating the type-checker to support passive events for this to pass

@wassgha wassgha force-pushed the video-dock-ui branch 3 times, most recently from b90a2d6 to 1440784 Compare August 1, 2017 00:48
@erwinmombay
Copy link
Member

i am close to updating. theres a dozen of broken types now though that i need to fix

@wassgha wassgha changed the title Video Docking Minimized Controls Passive event listener wrapper Aug 9, 2017
@wassgha wassgha requested a review from dvoytenko August 10, 2017 00:58
* @return {!UnlistenDef}
*/
export function listenOnce(element, eventType, listener, opt_capture) {
export function listenOnce(element, eventType, listener,
Copy link
Contributor

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


// Test whether browser supports the passive option or not
let passiveSupported = false;
try {
Copy link
Contributor

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

@@ -50,11 +50,12 @@ export function createCustomEvent(win, type, detail, opt_eventInit) {
* @param {string} eventType
* @param {function(!Event)} listener
* @param {boolean=} opt_capture
Copy link
Member

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

Copy link
Contributor Author

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!

Copy link
Member

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.

@@ -41,11 +43,34 @@ export function internalListenImplementation(element, eventType, listener,
throw e;
}
};

// Test whether browser supports the passive option or not
let passiveSupported = false;
Copy link
Member

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.

// Test whether browser supports the passive option or not
let passiveSupported = false;
try {
const options = Object.defineProperty({}, 'passive', {
Copy link
Member

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.

@cramforce
Copy link
Member

Usage in #10901

@wassgha
Copy link
Contributor Author

wassgha commented Aug 14, 2017

Ready for final review, will need to revert back to using AddEventListenerOptions instead of Object when it is recognized as a valid type.
I have not found any instances where we currently use the capture parameter, please double check for side effects.

@@ -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
Copy link
Member

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.

* addEventListener or not
* @enum {string}
*/
const optTest = {
Copy link
Contributor

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.

};
const optsSupported = detectEvtListenerOptsSupport();
let capture = false;
if (opt_evtListenerOpts && opt_evtListenerOpts.capture) {
Copy link
Contributor

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

try {
let optsSupported = self.optsSupported;
const options = Object.defineProperty({}, 'capture', {
get: function() {
Copy link
Contributor

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;
  },
}

optsSupported = optTest.SUPPORTED;
},
});
self.addEventListener('test-opts', null, options);
Copy link
Contributor

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.

* @suppress {checkTypes}
*/
export function detectEvtListenerOptsSupport() {
if (!self.optsSupported) {
Copy link
Contributor

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
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Contributor

@aghassemi aghassemi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one request

/**
* Resets the test for whether addEventListener supports options or not.
*/
export function resetEvtListenerOptsSupport() {
Copy link
Contributor

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

Copy link
Contributor

@jridgewell jridgewell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits.

// Only run the test once
if (self.optsSupported != optTest.NOT_RUN) {
return self.optsSupported == optTest.SUPPORTED;
if (typeof optsSupported != 'undefined') {
Copy link
Contributor

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.

*/
export function detectEvtListenerOptsSupport() {
// Only run the test once
if (typeof optsSupported != 'undefined') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optsSupported !== undefined

optsSupported = true;
},
};
self.addEventListener('test-opts', null, options);
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up as in?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#removeEventListener

@wassgha wassgha force-pushed the video-dock-ui branch 2 times, most recently from a84a879 to a280211 Compare August 17, 2017 04:24
@wassgha wassgha added this to the Sprint H2 August milestone Aug 17, 2017
@aghassemi
Copy link
Contributor

test failure and we can merge after

@wassgha
Copy link
Contributor Author

wassgha commented Aug 17, 2017

For future reference, the test was failing because removeEventListener on the test was calling the getter of capture in options which was setting optsSupported to true even though addEventListener was stubbed to not accept options. Had to stub removeEventListener too.

@aghassemi
Copy link
Contributor

@cramforce Blocked on your review, PTAL

@aghassemi aghassemi merged commit 1ef6ae4 into ampproject:master Aug 18, 2017
cramforce added a commit that referenced this pull request Aug 31, 2017
cramforce added a commit to cramforce/amphtml that referenced this pull request Sep 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants